제네릭스(Generics)
제네릭스
-
자바5에 추가된 기능으로 타입에 얽매이지 않는 유연한 클래스 및 인터페이스의 설계에 도움을 주는 기능이다.
-
제네릭스는 클래스 내부에 사용할 데이터 타입을 외부에서 지정하는 기법 - 생활코딩
-
제네릭스는 다양한 타입의 객체들을 다루는 메소드나 컬렉션 클래스에 컴파일 시의 타입체크를 해주는 기능 - 자바의 정석
Type Parameter Naming Conventions
- E - Element (used extensively by the Java Collections Framework)
- K - Key
- N - Number
- T - Type
- V - Value
- S,U,V etc. - 2nd, 3rd, 4th types
제네릭스 인터페이스
public interface GenericsTest<V, E> {
V doSomethingWithLine(E line, V value);
}
<>안에 사용할 타입을 대문자로 선언하여 클레스에서 사용할 타입을 외부에서 지정하도록 한다.
바운디드 타입 파라미터
타입을 특정 타입으로 지정하겠다는 의미이다.
public class GenericsTest<E, T extends Number> {
T doSomethingWithLine(E line, T value);
}
사용할 제네릭 타입을 특정 클래스의 서브 클래스로 지정하는 방법
class ConA {}
interface InterB {}
interface InterC {}
public class TestClass<T extends ConA & InterB & InterC> {
}
다중 바운디드 타입으로 자바 상속의 특성에 따라 하나의 클래스를 상속할 수 있고 인터페이스로는 여러개를 적용할 수 있다.
와일드카드 타입?
와일드카드 타입을 통해 제네릭스의 공변성, 반공변성, 무공변성을 표현할 수 있다.
제네릭에서의 공변성, 반공변성, 무공변성
변성 | 의미 |
---|---|
공변성(Covariant) | T'가 T의 서브타입이면, C<T`>는 C<? extends T>의 서브타입이다. |
반공변성(Contravariant) | T`가 T의 서브타입이면, C<T>는 C<? super T>의 서브타입이다. |
무공변성, 불변성(Invariant) | C와 C<T`>는 아무런 관계가 없다. |
Upper Bounded 와일드 카드 (공변성)
- 변수의 타입의 제한 조건을 완화하기 위해 Upper bounded wildcard를 사용할 수 있다.
- 사용법: ? extends {원하는 타입}을 사용하면 된다. (여기서 extends는 implements를 동시에 의미한다.)
public static double sumOfList(List<? extends Number> list) {
double s = 0.0;
for (Number n : list)
s += n.doubleValue();
return s;
}
Lower Bounded 와일드 카드 (반공변성)
- Lower Bounded 와일드 카드는 알려지지 않은 타입에서 특정 타입까지 제한하거나 특정 타입의 super type까지 제한합니다. 지정된 타입의 서브타입은 사용할 수 없다.
- 사용법: <\? super {원하는 타입}> 을 사용하면 된다.
Unbounded 와일드카드를 사용하는 시나리오
- Object 클래스가 제공하는 함수 기능을 사용하는 메소드를 작성하고 싶을 때
- 타입 파라미터에 의존하지 않는 제네릭스 클래스의 메소드를 이용한 코드를 작성할 때 (사실 Class<?>는 자주 사용되는데 대부분 Class
는 T에 의존하지 않기 때문이다)
❔ ‘?’는 클래스의 제네릭스 타입 파라미터로 가능할까?
❌ 클래스의 제네릭스 파라미터로 쓰이지는 않는다. 메소드에서나 쓰인다
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("asdf");
list.add("zxcv");
printList(list);
}
public static void printList(List<Object> list) {
for(Object o : list) {
System.out.println(o);
}
}
}
위 코드 같은 경우 list 변수가 printList의 파라미터로 적합하지 않아 오류가 나게된다.
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("asdf");
list.add("zxcv");
printList(list);
}
public static void printList(List<?> list) {
for(Object o : list) {
System.out.println(o);
}
}
}
List<?>는 List<String>에 호환되므로 알맞게 실행된다.
제네릭 메소드로 만든 Pair
public class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) { this.key = key; }
public void setValue(V value) { this.value = value; }
public K getKey() { return key; }
public V getValue() { return value; }
}
public class Util {
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
댓글남기기