[Java 언어 활용] 3.1 제네릭(Generic)
제네릭(Generic)은 여러 형식에 맞게 재사용할 수 있는 코드를 정의하는 기술을 말합니다. 제네릭 코드를 정의할 때는 가상의 형식 이름을 <가상 형식 이름> 처럼 정의하고 사용하는 곳에서 어떠한 형식에 관한 코드를 사용할 것인지 명시하여 사용하는 기법입니다.
먼저 제네릭 클래스를 정의할 때는 클래스명 뒤에 <가상 형식 이름>을 명시하여 만들 수 있습니다.
class 클래스명<가상 형식 이름>{
}
사용하는 곳에서는 가상 형식 이름 대신 구체적으로 사용할 형식을 결정하여 <사용할 형식 이름>을 명시하여 사용합니다.
클래스명<사용할 형식 이름> 변수명 = new 클래스명<사용할 형식 이름>();
다음은 정수 형식을 보관하는 정수 적 배열 클래스와 제네릭 형식으로 원하는 형식을 사용자가 결정할 수 있는 제네릭 동적 배열 클래스를 정의한 것입니다.
▷ 소스 3.1 정수 동적 배열과 제네릭 동적 배열 예
//IntDArray.java //정수 동적 배열 public class IntDArray { int[] buffer; int capacity; int usage; public IntDArray(int capacity){ this.capacity = capacity; buffer = new int[capacity]; usage = 0; } public boolean isEmpty(){ return usage == 0; } public boolean isFull(){ return usage == capacity; } public int size(){ return usage; } public boolean add(int value){ if(isFull()){ return false; } buffer[usage] = value; usage++; return true; } public void viewAll(){ String outstr = String.format("저장소 크기:%d 보관개수:%d",capacity,usage); System.out.println(outstr); for(int i = 0; i<usage;i++){ System.out.print(buffer[i]+" "); } System.out.println(); } } |
//DArray.java //제네릭 동적 배열 public class DArray<datatype> { Object[] buffer; int capacity; int usage; public DArray(int capacity){ this.capacity = capacity; buffer = new Object[capacity]; usage = 0; } public boolean isEmpty(){ return usage == 0; } public boolean isFull(){ return usage == capacity; } public int size(){ return usage; } public boolean add(datatype value){ if(isFull()){ return false; } buffer[usage] = value; usage++; return true; } public void viewAll(){ String outstr = String.format("저장소 크기:%d 보관개수:%d",capacity,usage); System.out.println(outstr); for(int i = 0; i<usage;i++){ System.out.print(buffer[i]+" "); } System.out.println(); } } |
//Program.java //정수 동적 배열과 제네릭 동적 배열 public class Program { public static void main(String[] args){ System.out.println("==Test IntDArray==="); IntDArray idarr = new IntDArray(10); idarr.viewAll(); idarr.add(3); idarr.viewAll(); idarr.add(2); idarr.viewAll(); idarr.add(6); idarr.viewAll();
System.out.println("==Test DArray<integer>==="); DArray<Integer> darr = new DArray<Integer>(10); darr.viewAll(); darr.add(3); darr.viewAll(); darr.add(2); darr.viewAll(); darr.add(6); darr.viewAll();
System.out.println("==Test DArray<String>==="); DArray<String> darr2 = new DArray<String>(10); darr2.viewAll(); darr2.add("Hello"); darr2.viewAll(); darr2.add("언제나 휴일"); darr2.viewAll(); darr2.add("ehpub.co.kr"); darr2.viewAll(); } } |
▷ 소스 3.1 실행 결과
==Test IntDArray=== 저장소 크기:10 보관개수:0
저장소 크기:10 보관개수:1 3 저장소 크기:10 보관개수:2 3 2 저장소 크기:10 보관개수:3 3 2 6 ==Test DArray<integer>=== 저장소 크기:10 보관개수:0
저장소 크기:10 보관개수:1 3 저장소 크기:10 보관개수:2 3 2 저장소 크기:10 보관개수:3 3 2 6 ==Test DArray<String>=== 저장소 크기:10 보관개수:0
저장소 크기:10 보관개수:1 Hello 저장소 크기:10 보관개수:2 Hello 언제나 휴일 저장소 크기:10 보관개수:3 Hello 언제나 휴일 ehpub.co.kr
|
또한 메소드의 특정 인자 형식을 제네릭 형태로 표현할 수도 있습니다. 이 때 메소드 리턴 형식 이름 앞에 <가상 형식 이름>으로 명시하여 작성합니다. 이러한 메서드를 제네릭 메서드라 부르며 호출하는 곳에서는 실제 값 형식을 알고 있기 때문에 형식 이름을 명시할 필요가 없습니다.
다음은 제네릭 메서드를 정의하여 사용한 예입니다. 여기서 제네릭 메서드는 전달받은 값을 출력한 후에 다시 그 값을 반환하는 메서드로 큰 의미는 없습니다. 단지 제네릭 메서드를 보여주기 위함입니다.
▷ 소스 3.2 제네릭 메서드
//제네릭 메서드 public class Program { static <T> T Foo(T value){ System.out.print(value); System.out.println(); return value; } public static void main(String[] args){ int i = 10; int re = Foo(i); System.out.println("re:"+re); } } |
▷ 소스 3.2 실행 결과
10 re:10 |
제네릭을 표현할 때 특정한 규약을 따르는 형식만 사용할 때도 있습니다. 만약 정렬 메서드를 제공하려면 개체의 값을 비교할 수 있어야 할 것입니다. Java 라이브러리에는 Comparable 인터페이스를 정의하고 있고 비교할 수 있는 형식을 정의할 때 Comparable 인터페이스를 기반으로 구현 클래스를 정의하는 것을 권장합니다. 따라서 정렬 메서드를 제공할 때 최소한 Comparable 인터페이스를 기반의 구현 클래스로 한정할 필요가 있습니다. 주의할 점은 인터페이스일 때도 <가상 형식 이름 extends 특정 형식 이름> 형태로 표현해야 합니다.
다음은 정적 메서드 Sort의 입력 매개 변수로 Comparable 인터페이스로 한정한 제네릭 메서드를 구현한 예제입니다.
▷ 소스 3.3 Comparable 인터페이스로 한정한 제네릭 메서드 Sort
//Comparable 인터페이스로 한정한 제네릭 메서드 Sort public class Program { static <dt extends Comparable> void Sort(dt[] arr){
for(int i = arr.length; i>1; i--){ for(int j=1; j<i;j++){ if(arr[j].compareTo(arr[j-1])<0){ dt temp = arr[j-1]; arr[j-1] = arr[j]; arr[j] = temp; } } } } public static void main(String[] args){ String[] arr = {"홍길동", "강감찬", "을지문덕", "김구", "이순신"}; System.out.println("정렬 전"); for(int i = 0; i<arr.length;i++){ System.out.print(arr[i]+" "); } System.out.println();
Sort(arr);
System.out.println("정렬 후"); for(int i = 0; i<arr.length;i++){ System.out.print(arr[i]+" "); } System.out.println(); } } |
▷ 소스 3.3 실행 결과
정렬 전 홍길동 강감찬 을지문덕 김구 이순신 정렬 후 강감찬 김구 을지문덕 이순신 홍길동 |
'언어 자료구조 알고리즘 > 디딤돌 Java 언어 Part2 활용' 카테고리의 다른 글
[Java 언어 활용] 3.4.2 Vector를 이용하여 인덱스로 관리하기 (0) | 2016.12.10 |
---|---|
[Java 언어 활용] 3.4.1 Vector를 이용하여 특정 키 순으로 보관하기 (0) | 2016.12.10 |
[Java 언어 활용] 3.4 Vector 클래스 (0) | 2016.12.10 |
[Java 언어 활용] 3.3 Collection 인터페이스 (0) | 2016.12.10 |
[Java 언어 활용] 3.2 컬렉션 (0) | 2016.12.10 |
[Java 언어 활용] 3. 제네릭과 컬렉션 (0) | 2016.12.10 |
[Java 언어 활용] 2.5 예외 클래스 정의하기 (0) | 2016.12.08 |
[Java 언어 활용] 2.4 예외 발생에 관계없이 수행해야 할 코드는 finally 문 사용 (0) | 2016.12.08 |
[Java 언어 활용] 2.3 프로그램 방식으로 예외를 던지는 throw 문 (0) | 2016.12.08 |
[Java 언어 활용] 2.2 예외를 잡아서 처리하기 (0) | 2016.12.08 |