이 글은 유튜브 '자바의 정석 - 기초편'을 보고 정리한 글입니다.
📂content
1. 와일드 카드 <?>
- 하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능
ArrayList<? extends Product> list = new ArrayList<Tv>(); //OK
ArrayList<? extends Product> list = new ArrayList<Audio>(); //OK
ArrayList<Product> list = new ArrayList<Tv>(); // 에러. 대입된 타입 불일치
<? extends T> 와일드 카드의 상한 제한. 그외 그 자손들만 가능 (보통 많이 사용)
<? super T> 와일드 카드의 하한 제한. T와 그 조상들만 가능
<?> 제한 없음. 모든 타입이 가능. <? extends Object>와 동일
- 메서드의 매개변수에 와일드 카드를 사용
static Juice makeJuice(FruitBox<? extends Fruit> box) {
String tmp = "";
for(Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
System.out.println(Juicer.makeJuice(new FruitBox<Fruit>()));
System.out.println(Juicer.makeJuice(new FruitBox<Apple>()));
⍟실습
Ex12_4
더보기
package etc;
import java.util.ArrayList;
class Fruit2 { public String toString() { return "Fruit";}}
class Apple2 extends Fruit2 { public String toString() { return "Apple";}}
class Grape2 extends Fruit2 { public String toString() { return "Grape";}}
class Juice {
String name;
Juice(String name) { this.name = name + "Juice"; }
public String toString() { return name; }
}
class Juicer {
static Juice makeJuice(FruitBox2<? extends Fruit2> box) { //static method
String tmp = "";
for(Fruit2 f : box.getList())
tmp += f + " ";
return new Juice(tmp);
}
}
class Ex12_4 {
public static void main(String[] args) {
FruitBox2<Fruit2> fruitBox = new FruitBox2<Fruit2>(); //참조변수 제네릭타입 == 생성자 제네릭타입
// FruitBox2<Fruit2> fruitBox1 = new FruitBox2<Apple2>(); //에러
//Fruit2와 그 자손들(Apple, Grape)
FruitBox2<? extends Fruit2> fruitBox2 = new FruitBox2<Apple2>(); //OK.
FruitBox2<Apple2> appleBox = new FruitBox2<Apple2>();
fruitBox.add(new Apple2());
fruitBox.add(new Grape2());
appleBox.add(new Apple2());
appleBox.add(new Apple2());
System.out.println(Juicer.makeJuice(fruitBox));
System.out.println(Juicer.makeJuice(appleBox));
} // main
}
class FruitBox2<T extends Fruit2> extends Box2<T> {}
class Box2<T> {
ArrayList<T> list = new ArrayList<T>();
void add(T item) { list.add(item); }
T get(int i) { return list.get(i); }
ArrayList<T> getList() { return list; }
int size() { return list.size(); }
public String toString() { return list.toString();}
}
2. 지네릭 메서드
- 지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
static <T> void sort(List<T> list, Comparator<? super T> c)
- 클래스의 타입 매개변수<T>와 메서드의 타입 매개변수 <T>는 별개
class FruitBox<T> {
...
static <T> void sort(List<T> list, Comparator<? super T> c) {
...
}
}
지네릭 클래스와 지네릭 메서드의 타입 문자는 T로 동일하지만, 메서드의 T는 메서드 내에서만 사용이 가능하다. 즉, 이 둘은 다른 타입변수이다.
- 메서드를 호출할 때마다 타입을 대입해야(대부분 생략 가능)
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
...
System.out.println(Juicer.<Fruit>makeJuice(fruitBox));
System.out.println(Juicer.<Apple>makeJuice(appleBox));
Fruit 또는 그 자손만 가능하다고 제한함. 메소드의 FruitBox<T>의 T는 앞 부분의 <T extends Fruit>의 T이다.
- 메서드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가
System.out.println(<Fruit>makeJuice(fruitBox)); //에러. 클래스 이름 생략불가
System.out.println(this.<Fruit>makeJuice(fruitBox)); //OK
System.out.println(Juicer.<Fruit>makeJuice(fruitBox)); //OK
생략할 수 있을 때가 극히 드물다.
static Juice makeJuice(FruitBox<? extends Fruit> box) {
String tmp = "";
for(Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
위 코드는 <그림1>와 같은 의미이다. <그림1>은 지네릭 메서드이고, 위 코드는 와일드카드 메서드이다.
이 둘은 바꿔쓸 수 있다.
와일드 카드 : 하나의 참조변수로 대입된 타입이 다른 여러 제네릭 객체를 다룰 수 있게 함.
제네릭 메소드 : 메소드를 호출할 때마다 다른 제네릭 타입을 대입할 수 있게 함.
즉, 용도가 다르다. 그리고 와일드카드를 쓸 수 없을 때가 있다. 그래서 제네릭 메소드를 많이 쓴다.
출처
'🎥Back > 자바의 정석' 카테고리의 다른 글
[JAVA의 정석]열거형 (0) | 2024.01.19 |
---|---|
[JAVA의 정석]제네릭 형변환 (0) | 2024.01.19 |
[JAVA의 정석]Generics, Generics 클래스 (0) | 2024.01.18 |
[JAVA의 정석]Collections 클래스, 컬렉션 클래스 요약 (2) | 2024.01.17 |
[JAVA의 정석]HashMap (0) | 2024.01.17 |