-
java generic(2)대학/객체지향프로그래밍 2022. 12. 10. 01:15
- Generic Method
지금까지는 클래스에서 제네릭의 사용법을 살펴봤는데, 메서드에서도 제네릭을 사용할 수 있다.
일반 클래스 내부에서도 메서드의 매개변수나 리턴 값을 제네릭 매개변수로 정의할 수 있다.
class GenMethDemo { // Comparable<T>는 java.lang에서 선언된 클래스로 T를 비교 가능한 상태로 만들어준다. // V타입 배열 안에 T타입 변수를 넣기 위해 V extends T. static <T extends Comparable<T>, V extends T> boolean isIn(T x, V[] y) { for(int i=0; i < y.length; i++) if(x.equals(y[i])) return true; return false; } public static void main(String[] args) { // Use isIn() on Integers. Integer[] nums = { 1, 2, 3, 4, 5 }; if(isIn(2, nums)) System.out.println("2 is in nums"); // 실행 if(!isIn(7, nums)) System.out.println("7 is not in nums"); System.out.println(); // Use isIn() on Strings. String[] strs = { "one", "two", "three", "four", "five" }; if(isIn("two", strs)) System.out.println("two is in strs"); // 실행 if(!isIn("seven", strs)) System.out.println("seven is not in strs"); // Types must be compatible. // if(isIn("two", nums)) // isIn() > V extends T에서 컴파일 에러 발생. // System.out.println("two is in strs"); } }
이렇게하면 isIn 메서드를 사용할 때, 타입을 신경쓰지 않고 사용할 수 있다.
class GenCons { private double val; <T extends Number> GenCons(T arg) { val = arg.doubleValue(); } void showVal() { System.out.println("val: " + val); } } class GenConsDemo { public static void main(String[] args) { GenCons test = new GenCons(100); GenCons test2 = new GenCons(123.5F); test.showVal(); // val: 100 test2.showVal(); // val: 123.5 } }
생성자 함수 역시 제네릭으로 만들 수 있다.
- Generic Interface
// A Min/Max interface. interface MinMax<T> { T min(); T max(); } class MyClass<T extends Comparable<T>> implements MinMax<T> { T[] vals; MyClass(T[] o) { vals = o; } public T min() { T v = vals[0]; for(int i=1; i < vals.length; i++) if(vals[i].compareTo(v) < 0) v = vals[i]; return v; } public T max() { T v = vals[0]; for(int i=1; i < vals.length; i++) if(vals[i].compareTo(v) > 0) v = vals[i]; return v; } } class GenIFDemo { public static void main(String[] args) { Integer[] inums = {3, 6, 2, 8, 6 }; Character[] chs = {'b', 'r', 'p', 'w' }; MyClass<Integer> iob = new MyClass<Integer>(inums); MyClass<Character> cob = new MyClass<Character>(chs); System.out.println("Max value in inums: " + iob.max()); System.out.println("Min value in inums: " + iob.min()); System.out.println("Max value in chs: " + cob.max()); System.out.println("Min value in chs: " + cob.min()); } }
인터페이스 역시 제네릭으로 만들 수 있다.
- row 타입
사실 필요없는데, 제네릭이 없던 JDK 5 이전 레거시 코드와 호환되게 하기 위해 사용한다.
class Gen<T> { T ob; Gen(T o) { ob = o; } T getOb() { return ob; } } class RawDemo { public static void main(String[] args) { // 익히 쓰는 제네릭 방식 Gen<Integer> iOb = new Gen<Integer>(88); Gen<String> strOb = new Gen<String>("Generics Test"); // 제네릭 raw 타입 Gen raw = new Gen(Double.valueOf(98.6)); double d = (Double) raw.getOb(); // Object 타입이 반환된다. System.out.println("value: " + d); // run-time error: 반환 타입은 Object지만, 내용물은 Double임. // Double -> Integer로 캐스팅될 수 없음. // int i = (Integer) raw.getOb(); strOb = raw; // OK: Gen<T>에 Gen을 할당하는 것은 된다. // run-time error: Gen<String>이라 해도 가리키는 대상은 Double을 갖고있음. // String str = strOb.getOb(); raw = iOb; // OK: Gen에 Gen<T>를 할당하는 것은 된다. // run-time error: Integer -> Double로 캐스팅 될 수 없음. // d = (Double) raw.getOb(); } }
다만 Gen<Object>와 같이 type safety는 보장되지 않는다.
- Extends Generic Class
제네릭 매개변수를 쓰는 클래스간 상속이 가능하다.
상속받은 자식 클래스는 부모 클래스가 쓰는 제네릭 외에 다른 타입을 추가할 수 있다.
심지어 제네릭을 쓰는 클래스가 일반 클래스를 상속할 수 있다.
class Gen<T> { T ob; Gen(T o) { ob = o; } T getOb() { return ob; } } class Gen2<T, V> extends Gen<T> { V ob2; Gen2(T o, V o2) { super(o); ob2 = o2; } V getOb2() { return ob2; } } class HierDemo { public static void main(String[] args) { // Create a Gen2 object for String and Integer. Gen2<String, Integer> x = new Gen2<String, Integer>("Value is: ", 99); System.out.print(x.getOb()); // value is: System.out.println(x.getOb2()); // 99 } }
단, 자식 클래스의 타입 변수는 부모 클래스의 타입 변수를 포함해야 한다.
- 제네릭 유의점
class Gen<T> { T ob; Gen() { ob = new T(); // error } }
1. 타입 매개변수는 객체화 할 수 없다.
class Wrong<T> { static T ob; // error static T getOb() { // error return ob; } static <T> T mySelf(T x) { // ok return x; } }
2. 제네릭 멤버 변수를 static으로 선언할 수 없고, static 메서드는 제네릭 멤버 변수를 사용할 수 없다.
(동적으로 제네릭을 생성하기 전에 static으로 제네릭 타입을 결정하는 것이 불가능하기 때문)
단, 제네릭 메서드는 사용 가능하다.
(리턴 형식을 직접적으로 제네릭 타입으로 정의는 불가능. 매개 변수 타입에 따라 동적으로 리턴 타입을 결정하는 것은 가능)
class Gen<T extends Number> { T ob; T[] vals; // OK Gen(T o, T[] nums) { ob = o; // vals = new T[10]; // wrong vals = nums; // OK } }
3. 제네릭 배열 변수는 선언 가능. 하지만 생성은 불가.
'대학 > 객체지향프로그래밍' 카테고리의 다른 글
java 네트워크 프로그래밍 (0) 2022.12.10 java lambda expression / 메서드 참조 (0) 2022.12.10 java generic(1) (0) 2022.12.09 java transient / volatile / instanceof / native / assert (0) 2022.12.09 java I/O (0) 2022.12.09