제네릭이란?

  • JDK 1.5에 등장
  • C++의 Templete, Typescript의 Generic 과 비슷하다.
  • 일반화된 타입 매개 변수로 클래스나 메서드를 선언하는 기법
  • Stack<T>, Map<T, K> 등이 있다

와일드 카드

  • 모든 타입을 대신할 수 있는 와일드카드 타입
  • Stack<?> q = new ArrayDeque();
  • Unknown type이다.

한정적 와일드 카드( Bounded Wildcard )

특정 타입을 기준으로 상한 범위와 하한 범위를 지정하는 와일드 카드.

상황을 이해하기 위해 다음과 같이 3가지 클래스가 존재한다고 가정.

class MyGrandParent {}
class MyParent extends MyGrandParent {}
class MyChild extends MyParent {}
class AnotherChild extends MyParent {}

상한 경계 와일드 카드

void printCollection(Collection<? extends MyParent> c) {
	for( MyChild e : c ) { soutp(e); }	      // 컴파일 오류
	for( MyParent e : c ) { soutp(e); }	      // OK
	for( MyGrandParent e : c ) { soutp(e); }	// OK
	for( Object e : c ) { soutp(e); }	        // OK
}
  • extends를 사용해서 와일드카드 타입의 최상위 타입을 정의함으로써 상한 경계를 결정
  • extends는 자식 클래스를 만들 때 사용되므로, 위의 <? extends MyParent>로 가능한 타입은 MyParent미지의 모든 MyParent 자식 클래스들이다.
  • 컬렉션 c에서 꺼내는 객체가 반드시 MyChild가 아닌 AnotherChild 일 수 있기 때문에 불가능!
  • 하지만 적어도 MyParent 타입은 확실하므로 부모 타입으로 꺼내는 것은 문제가 없다.
void addElement(Collection<? extends MyParent> c) {
    c.add(new MyChild());        // 불가능(컴파일 에러)
    c.add(new MyParent());       // 불가능(컴파일 에러)
    c.add(new MyGrandParent());  // 불가능(컴파일 에러)
    c.add(new Object());         // 불가능(컴파일 에러)
}
  • 자식 타입을 특정할 수 없어 불가능하다.
  • 이 경우, 상한 경계가 아닌 하한 경계를 지정하여 최소한 MyParent 타입 임을 보장하면 해결된다.

하한 경계 와일드 카드

void addElement(Collection<? super MyParent> c) {
    c.add(new MyChild());
    c.add(new MyParent());
    c.add(new MyGrandParent());  // 불가능(컴파일 에러)
    c.add(new Object());         // 불가능(컴파일 에러)
}
  • super를 사용해 와일드카드의 최하위 타입을 정의하여 하한 경계를 설정
  • 컬렉션 c가 갖는 타입은 적어도 MyParent의 부모 타입들이다.
    • MyParent의 자식 타입은 컬렉션에 추가할 수 있다.
void printCollection(Collection<? super MyParent> c) {
	for( MyChild e : c ) { soutp(e); }	      // 컴파일 오류
	for( MyParent e : c ) { soutp(e); }	      // 컴파일 오류
	for( MyGrandParent e : c ) { soutp(e); }	// 컴파일 오류
	for( Object e : c ) { soutp(e); }	        // OK
}
  • 부모 타입을 특정할 수 없어 모든 부모 타입들에 컴파일 에러가 발생한다.
  • Object의 경우, Java의 모든 객체의 부모임이 명확하므로, 특별하게 가능하다.

PECS( Producer-Extends, Consumer-Super ) 공식

// Produce
void printCollection(Collection<? extends MyParent> c) {
    for (MyParent e : c) {
        System.out.println(e);
    }
}

// Consume
void addElement(Collection<? super MyParent> c) {
    c.add(new MyParent());
}
  • 와일드카드 타입의 객체를 생성 및 만들 경우( Produce ) extends
  • 갖고 있는 객체를 컬렉션에 사용 또는 소비할 경우( Consume ) super

출저

profile
백엔드 개발자 지망생

0개의 댓글