Post

제네릭

제네릭이란

JDK 1.5에 도입된 컴파일 시 타입체크를 해주는 기능. 클래스와 메서드에 선언할 수 있다.

장점

객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여준다.

용어

1
2
3
class Car<T> {
    ...
}

위와 같은 클래스가 정의되어 있다고 할 때

Car<T>
제네릭 클래스
Car
원시 타입
T
타입 매개변수

컴파일러가 소스파일을 컴파일하면 타입 매개변수를 대입된 타입으로 변경하고 제네릭 선언을 제거하여 .class 파일에는 제네릭 선언이 없다.

주의사항

  1. static 변수와 static 메서드에는 타입 매개변수를 사용할 수 없다.

    1
    2
    3
    4
    
     class Car<T> {
         static T speed;  // 에러
         static int speedUp(T t1) { ... }  // 에러
     }
    
  2. 제네릭 배열 참조변수를 정의하는 것은 가능하지만 new 키워드로 제네릭 배열을 생성할 수는 없다.

    1
    2
    3
    4
    5
    6
    7
    
     class Car<T> {
         T[] arr;  // 가능
         void temp() {
             T[] copy = new T[arr.length];  // 에러
             ...
         }
     }
    

    제네릭 배열을 생성해야할 때는 리플렉션 API를 사용하거나 Object 배열을 생성해서 복사한 후 형변환하는 방법을 사용해야 한다.

    ArrayList 클래스의 toArray(T[] a) 메서드를 참고하면 제네릭 배열의 실제 구현을 볼 수 있다.

  3. 제네릭 클래스의 객체를 생성하거나 사용할 때 상속에 주의해야 한다.

    1. Fruit이 부모 / Apple이 자식 일 때
      1
      
       Box<Fruit> fruitBox = new Box<Apple>();  // 상속이라도 안된다
      
    2. Box는 부모 / AppleBox는 자식 일 때
      1
      
       Box<Apple> appleBox = new AppleBox<Apple>();  // 다형성으로 가능
      
    3. Fruit이 부모 / Apple이 자식일 때
      1
      2
      
       Box<Fruit> fruitBox = new Box<>();
       fruitBox.add(new Apple());  // 다형성으로 가능
      

타입 제한

타입 매개변수에 대입할 수 있는 타입을 제한할 수 있다.

1
2
3
class Box<T extends Fruit> {
    ...
}

위와 같이 선언된 제네릭 클래스는 타입 매개변수에 Fruit 과 그 자식 타입만 대입할 수 있다.

1
2
3
class Box<T extends Eatable> {
    ...
}

이렇게 하면 타입 매개변수에 Eatable 이라는 인터페이스를 구현한 타입만 대입할 수 있다.

인터페이스지만 implements 를 사용하지 않고 여전히 extends 키워드를 사용한다.

여러 인터페이스를 구현한 타입을 타입 매개변수에 대입하게 하려면 아래와 같이 하면 된다.

1
class Box<T extends Eatable & Saleable> { ... }

와일드 카드

타입 매개변수를 사용할 수 없는 일반 클래스에서 제네릭 클래스를 매개변수로 받아서 처리하는 메서드를 정의할 때 사용

1
2
3
class Juicer {
    static int makeJuice(Box<? extends Fruit> box) { ... }
}
<? extends T>
T 와 그 자식 타입으로 와일드카드 제한
<? super T>
T 와 그 부모 타입으로 와일드카드 제한
<?>
와일드카드 타입 제한 없음. <? extends Object> 와 동일

와일드카드는 타입 제한과 달리 & 기호를 사용할 수 없다.

제네릭 메서드

메서드의 선언부에 제네릭 타입이 선언된 메서드를 제네릭 메서드라고 한다.

제네릭 메서드는 제네릭 클래스가 아닌 클래스에도 정의할 수 있고 static 키워드가 있어도 오류가 발생하지 않는다.

제네릭 클래스에 제네릭 메서드가 정의되어 있지만 제네릭 클래스의 T 와 제네릭 메서드의 T 는 별개의 것이다.

대표적으로 Collections 클래스의 sort 메서드가 있다.

1
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
This post is licensed under CC BY 4.0 by the author.