JAVA
[Java.5-2] 제네릭 메소드와 와일드 카드
식빵민
2022. 5. 20. 21:00
Generic Method : 타입 매개변수를 사용하는 메소드
- 제네릭 클래스 뿐 아니라 일반 클래스의 멤버도 될 수 있다.
- 제네릭 메소드를 정의할 때에는 타입 매개변수를 반환 타입 앞에 위치시킨다.
리턴 타입 앞에 <> 기호를 추가한다.
제네릭 메소드는 매개 타입 또는 리턴 타입으로 타입 매개변수를 사용한다.(매개변수 or 리턴타입 일반화)
class MyArray{
static <T> void swap(T[]arr, int i, int j){
T tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
- 제네릭 메소드를 호출할 때에는 구체적인 타입을 생략할 수 있다.
Integer []arr = {1,2,3,4,5};
MyArray.swap(arr,0,4);
한정된 타입 매개변수
선언부의 타입 매개변수에 대해 특정 타입으로 제한하고 싶은 경우 -> 타입 한정 가능
- extends 클래스명(or 인터페이스명)
인터페이스인 경우에도 extends 사용 - T가 제한되므로, T에서 접근 가능한 메소드의 종류는 한정됨
ex. Number 클래스(추상클래스) -> Wrapper클래스의 슈퍼클래스, 8개의 기본타입에 대응되는 클래스
class MyMath{
static <T extends Number> double getAverage (T[]arr){
double a = 0;
for(int i =0;i<arr.length;i++){
a += arr[i].doubleValue();
}
a = a/arr.length;
return a;
}
}
static<T> double getAverage(T[]arr){
arr[].doubleValue();//!!오류!!
//어떤 타입의 배열이 들어올지 모르기 때문에 접근 가능한 메소드에 제한이 있음
}
제네릭 클래스 객체 생성과 전달
class MyClass<T extends Number>{
T val;
void set(T a){val = a;}
T get(){return val;}
}
MyClass<Integer>n1 = new MyClass<Integer>();
MyClass<Double>n2 = new MyClass<Double>();
n1.set(3);
n2.set(3.3);
printDouble(n1);
printDouble(n2);
public class GenericTest{
static void printDouble(MyClass<Number>n){//!오류! -> 와일드 카드 사용해야함!
String data = n.get().doubleValue();
System.out.print(data);
}
}
와일드 카드 : 하나의 참조변수로 여러 다른 타입변수를 가진 제네릭 클래스 객체를 참조할 수 있는 방법
- Unbounded wildcards : <?>
<?> 사용
? 자리에는 아무 타입이나 들어갈 수 있다.
MyClass<?> n;
n = new MyClass<Double>();
n = new MyClass<Integer>();
n = new MyClass<String>();
public class GenericTest{
static void printNumber(MyClass<?>n){
String data = n.get().doubleValue();
System.out.print(data);
}
}
- Upper bounded wildcard : extends 키워드를 사용하여 슈퍼클래스를 명시한다.
? extends ~
?의 슈퍼클래스에 ~가 있어야함
MyClass<? extends Number> n;
n = new MyClass<Double>();
n = new MyClass<Integer>();
n = new MyClass<String>();
// Number 클래스는 Double, Integer, String 클래스의 슈퍼클래스
- Lower bounded wildcard : super 키워드를 사용하여 서브클래스를 명시한다.
? super ~
?의 서브클래스에 ~가 있어야함
MyClass<? super Number> n;
n = new MyClass<Object>(); // Object자리에 Wrapper 클래스 못옴
// Number클래스는 Object 클래스의 서브클래스
와일드 카드와 제네릭 메소드의 차이
//Wildcard
static double max1(MyClass <? extends Number>n1, MyClass <? extends Number>n2){
double dn1 = n1.get()doubleValue();
double dn2 = n2.get()doubleValue();
if(dn1 > dn2) return dn1;
else return dn2;
}
//Generic
static double max2(MyClass <T>n1, MyClass <T>n2){
double dn1 = n1.get()doubleValue();
double dn2 = n2.get()doubleValue();
if(dn1 > dn2) return dn1;
else return dn2;
}
MyClass<Integer>n1 = new MyClass<Integer>();
MyClass<Integer>n2 = new MyClass<Integer>();
n1.set(10);
n2.set(11.1);
System.out.println(max1(n1,n2));// !성공!
// n1, n2 가 Integer, Double 로 각각 달라도 상관없음
System.out.println(max2(n1,n2));// !오류!
// n1, n2 가 타입이 같아야됨
제네릭 주의사항
- 제네릭 타입변수로 객체 생성이 불가하다.
제네릭 타입변수 레퍼런스는 선언 가능
T a; // 가능
a = new T();// 불가능
T a = new Integer(10);// 가능
- 제네릭 타입변수로 배열 생성 불가
선언은 가능
매개변수로의 제네릭 타입 배열은 사용 가능
T[] a; // 가능
T[] a = new T[10]; // 불가능
T[] a = new Integer[10]; // 가능
public void myArray(T[] a){...}// 가능