제네릭스

  • 자바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());
    }
}

태그:

카테고리:

업데이트:

댓글남기기