Generic
목차
- 제네릭이란?
- 제네릭 타입
- 제네릭 메서드
- 와일드카드
- 제네릭 타입 소거
1. 제네릭 이란?
- 컴파일 타임에 타입을 체크함으로써 코드의 안정성을 높여주는 기능
List<T> // 타입 매개 변수
List<String> stirngList = new ArrayList<String>();
// 매개변수화된 타입
1) 컴파일 타임에 강력한 타입 검사
List stringList = new ArrayList<>();
stringList.add("BoB");
stringList.add(1);
String result = (String) stringList.get(0) + (String) stringList.get(1); // Runtime Error !
List<String> stringList = new ArrayList<>();
stringList.add("BoB");
stringList.add(1); // Compile Error !
2) 캐스팅(타입 변환) 제거
List stringList = new ArrayList<>();
stringList.add("BoB");
String result = (String) stringList.get(0);
List<String> stringList = new ArrayList<>();
stringList.add("BoB");
String result = stringList.get(0);
3) 변성
1) 배열 vs 제네릭 타입
Object[] objectArray = new Integer[1];
List<Object> objectList = new ArrayList<Integer>(); // Compile Error !
2) 무공변(Invariance) - <T>
- 타입 B가 타입 A의 하위 타입일때, Category
<B>
가 Category<A>
의 하위 타입이 아닌 경우.
- 즉 아무런 관계가 없다.
3) 공변(Convariance) - <? extends T>
- 타입 B가 타입 A의 하위 타입일 때
- Category
<B>
가 Category<A>
의 하위 타입인 경우.
4) 반공변(Contravariance) - <? super T>
- 타입 B가 타입 A의 하위 타입일 때
- Category
<B>
가 Category<A>
의 상위 타입인 경우.
2. 제네릭 타입 (Generic Types)
1) Class<T>
interface<T>
class Category {
private Object object;
public void set(Object object){
this.object = object;
}
public Object get(){
return object;
}
}
class Category<T>{
private T t;
public void set(T t){
this.t = t;
}
public T get(){
return t;
}
}
3. 제네릭 메서드 (Generic Methods)
class NoodleCategory<T>{
private T t;
public void set(T t){
this.t = t;
}
public T get(){
return t;
}
public <T> void printClassName(T t){
System.out.println("클래스 필드에 정의된 타입 = " + this.t.getClass().getName());
System.out.println("제네릭 메서드에 정의된 타입 = " + t.getClass().getName());
}
}
NoodleCategory<Noodle> noodleCategory = new NoodleCategory<>();
noodleCategory.set(new Noodle());
noodleCategory.printClassName(new Pasta());
1) 제네릭 타입 제한의 필요성
class NoodleCategory<T>{
private T t;
public void set(T t){
this.t = t;
}
public T get(){
return t;
}
}
NoodleCategory<Noodle> noodleCategory = new NoodleCategory<>(); // OK
NoodleCategory<Coke> cokeNoodleCategory = new NoodleCategory<>(); // ????
2) 제한된 제네릭 타입
class NoodleCategory<T extends Noodle>{
private T t;
public void set(T t){
this.t = t;
}
public T get(){
return t;
}
}
NoodleCategory<Noodle> noodleCategory = new NoodleCategory<>();
NoodleCategory<Ramen> ramenNoodleCategory = new NoodleCategory<>(); // OK
NoodleCategory<Coke> cokeNoodleCategory = new NoodleCategory<>(); // Compile Error !
4. 와일드 카드
1) <?>
Unbounded Wildcards
2) <? extends Noodle>
Upper Bounded Wildcards
3) <? super Noodle>
Lower Bounded Wildcards
4) 제한
class NoodleCategory<T>{
private T t;
public void set(T t){
this.t = t;
}
public T get(){
return t;
}
}
class CategoryHelper {
public void popNoodle(Category<? extends Noodle> category){
Noodle noodle = category().get(); // 꺼내는 건 OK
category.set(new Noodle()); // 저장은 NO
}
public void pushNoodle(Category<? super Noodle> category){
category.set(new Noodle()); // 저장은 OK
Noodle noodle = category.get(); // 꺼내는건 NO
}
}
4-1) 언제 무엇을 써야할까?
- PECS
- producer - extends, consumer - super
5) 와일드 카드 producer - extends
class NoodleCategory<E>{
private List<E> list = new ArrayList<>();
public void pushAll(Collection<? extends E> box){
for(E e : box){
list.add(e);
}
}
}
6) 와일드 카드 consumer - super
class NoodleCategory<E>{
private List<E> list = new ArrayList<>();
public void popAll(Collection<? super E> box){
box.addAll(list);
list.clear();
}
}
5. 제네릭 타입 소거
- 타입 매개변수의 경계가 없는 경우에는 Object
- 경계가 있는 경우에는 경계 타입으로 타입 파라미터를 변경
- 타입 안전성을 유지하기 위해 필요한 경우 타입 변환 추가
- 제네릭 타입을 상속 받은 클래스의 다형성을 유지하기 위해 Bridge method 생성
출처
그린론의 제네릭
댓글남기기