간단히 말해서 하나의 클래스로 여러가지 자료형을 다 이용할 수 있게 하는 형식의 클래스이다.
Java를 조금 써 봤다면
HashSet<Integer>
같은 자료형을 다뤄 봤을텐데, 이 HashSet클래스를 타고 가 보면 Integer는 온데 간데 없고 HashSet<E>
라고 떡 하니 클래스 선언이 되어 있는데, 이게 바로 제네릭 클래스로 선언이 된 것이다.
제네릭 클래스를 사용하면
와 같은 이점이 있다.
public class Box<T> {
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
public interface Pair<K, V> {
public K getKey();
public V getValue();
}
public class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}
제네릭 클래스와 다를 거 하나 없지만, 제네릭 변수의 범위가 해당 메소드로 한정된다는 것만이 다르다.
그런데, 클래스 내 필드값이 특정 자료형으로 고정이 되어 있다면 이걸 굳이 제네릭 메소드를 이용해 처리 할 필요는 없기 때문에 사실상 static 메소드에서 많이 활용한다.
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o);
}
}
E, T, K, V 등등이 있는데, 정해진 규칙 따윈 없고 전부 convention에 불과하다.
다 마음에 안 들면 Z로 해도 되고, L로 해도 된다.
다만 convention을 지키는 데에서 오는 이점도 있으니, 지킬 수 있다면 지키는 편이 좋겠다.
등이 관련된 문자이다.
제네릭 타입에 extends/super 키워드를 사용하면 그 클래스와 그 클래스를 상속받는 자식클래스들만 이용 가능하게 할 수 있다.
<? extends T>
상한 제한 (upper bound): T와 그 자손들의 인스턴스만 매개변수로 가능
<? super T>
하한 제한 (lower bound) : T와 그 부모들의 인스턴스만 매개변수로 가능
interface Collection<E> {
public <T extends E> boolean addAll(Collection<T> c);
}
보통 제네릭 제한에 이용된다.
바로 위의 코드를 보면 저기서 사실 T는 아무 의미가 없다. 클래스는 E형으로 만들어 질 것이고, T는 E를 상속한 어떤 클래스라는 것인데 그냥 자리 메우기용 밖에는 되지 않는다.
이런 경우에 와일드 카드인 ?
를 사용할 수 있다.
interface Collection<E> {
public <E> boolean addAll(Collection<? extends E> c);
}
static List<List<? extends Shape>>
history = new ArrayList<List<? extends Shape>>();
public void drawAll(List<? extends Shape> shapes) {
history.addLast(shapes);
for (Shape s: shapes) {
s.draw(this);
}
}