티스토리 뷰

반응형

클래스와 인터페이스 선언에 타입 매개변수가 쓰이면 제네릭 클래스나 제네릭 인터페이스라 한다.

이들을 제네릭 타입이라고 한다.

로 타입 (raw type)

제네릭 타입을 하나 정의하면 그에 딸린 로 타입(raw type) 도 함께 정의된다.

제네릭 타입에서 타입 매개변수를 사용하지 않을 때를 로 타입이라고 한다. ex) List의 로 타입은 List

 

 

로 타입을 사용하면 안되는 이유

로 타입은 사용하지 않는 것이 좋다.

//Raw type
private final Collection stamps = ...; // Stamp 인스턴스만 취급한다.
stamps.add(new Coin(...)) // Coin 인스턴스를 add() 한다면 "unchecked call" 경고를 내뱉는다.

위 코드는 컴파일 오류 없이 실행이 잘 된다. 나중에 런타임에나 오류 여부를 알 수 있는 단점이 존재한다.

오류는 가능한 컴파일할때 발견하는 것이 좋다.

아래와 같이 제네릭을 활용하여 타입 안전성을 확보하는 것이 좋다. (컴파일 시에 오류 확인 가능)

//Generic type
private final Collection<Stamp> stamps = ...; // Stamp 인스턴스만 취급한다.
stamps.add(new Coin(...)) // Coin 인스턴스를 add() 한다면 컴파일 오류 발생

 

로 타입이 있는 이유

절대로 써서는 안되는 로 타입이 존재하는 이유는 호환성 때문이다.

자바에 제네릭이 있기 전 짠 코드와 잘 돌아가야하기 때문에 마이그레이션 호환성을 위해 로 타입을 지원하는 것이다.

 

 

매개변수화 타입 사용

  • List 는 안되지만 List 같이 임의 객체를 허용하는 매개변수화 타입은 괜찮다.
    List는 모든 타입을 허용한다는 의사를 컴파일러에 명확히 전달한 것이다.
  • List 를 매개변수로 받는 메서드에 List을 넘길 수 있지만, List를 매개변수로 받는 메서드에는 넘길 수 없다. (하위 타입 규칙)

 

비한정적 와일드 카드 타입(unbounded wildcard type) 을 사용하라

제네릭 타입을 쓰고 싶지만 실제 타입 매개변수가 무엇인지 신경쓰고 싶지 않다면 로 타입을 사용하지말고 비한정적 와일드카드 타입을 사용하라. (물음표로 타입을 작성)

//row type : 사용 금지
static int numElementsInCommon(Set set1, Set set2) {

}

//wildcard type
static int numElementsInCommon(Set<?> set1, Set<?> set2) {

}

어떤 타입이라도 담을 수 있는 범용적인 매개변수화 타입이다.

타입 불변식을 훼손하지 못하도록 막았기 때문에 다른 원소를 넣으려하면 컴파일시에 오류로 알려준다.

 

로 타입을 쓰는 예외 상황

  • class 리터럴에는 로 타입을 써야함 ex) List.class 나 List<?>.class 가 아닌 List.class 이다.
  • 런타임에는 제네릭 타입 정보가 지워지기 때문에 instanceof 연산자는 로 타입이나 비한정적 와일드카드 타입 외 매개변수화 타입에는 적용할 수 없음
if(o instanceof Set) {  //raw type
   Set<?> s = (Set<?>)o;  //wildcard type
}

o의 타입이 Set 임을 확인한 후에 와일드카드 타입인 Set<?>로 형변환해야한다.

 

 

결론

로 타입을 사용하면 런타임 예외가 발생할 수 있어서 사용 하면 안된다.

로 타입은 제네릭이 등장하기 전의 코드와의 호환성 때문에 존재하는것 뿐이다.

  • Set → 매개변수화 타입
  • Set<?> → 와일드카드 타입
  • Set → 로 타입 (제네릭 타입 시스템에 속하지 않음)
반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday