[Effective Java] 새로 작성하는 코드에서는 원천(raw) 타입을 사용하지 말자. |
-
하나 이상의 타입 매개변수(type parameter)를 선언하고 있는 클래스나 인터페이스를 제네릭 클래스 또는 제네릭 인터페이스라고 한다.
제네릭 클래스와 인터페이스를 합해서 제네릭 타입이라고 부른다.
각 제네릭 타입에서는 매개변수화 타입(parameterized type)들을 정의한다. ( <> 이용 )
실 타입 매개변수(actual type parameter)들은 제네릭 타입의 형식 타입 매개변수(formal type parameter)와 각각 대응된다.
( List<String> 에서 String 이 실 타입 매개변수이고, 기존 T 혹은 E 가 타입 매개변수이다. )
-
각 제네릭 타입에서는 원천(raw)타입을 정의하는데, 원천 타입은 실 타입 매개변수가 없이 사용되는 제네릭 타입의 이름을 말한다.
( List<String> 에서 원천타입은 List )
-
제네릭의 장점
컴파일 시점에 에러를 검출하기 좋다.
컬렉션에서 요소를 가져올 때, 삭제할 때 캐스팅 할 필요가 없다.
-
타입 매개변수를 주지 않고 원천타입으로 컬렉션이나 다른 제네릭 타입을 여전히 사용할 수 있다. ( 제네릭은 1.5 이후 등장 )
하지만 그렇게 해서는 안 된다.
원천 타입을 사용하면 제네릭의 장점인 타입 안전과 표현력 모두를 포기하는 것이다.
-
제네릭에는 서브 타입 규칙이 있다.
List<String> 은 원천 타입인 List 의 서브 타입이지만 매개변수 타입인 List<Object> 의 서브 타입은 아니다.
List 와 같은 원천 타입을 사용하면 타입의 안전성을 상실하게 되지만, List<Object> 와 같은 매개변수 타입을 사용하면 그렇지 않다.
-
제네릭 서브 타입을 보고 오히려 유연성이 떨어지는 것이 아니냐고 물을 수 있겠지만 그렇지 않다.
언바운드 와일드 카드 타입(unbounded wildcard type) 과 바운드 와일드 카드 타입(bound wildcard type) 이 있기 때문이다.
-
언바운드 와일드 카드 타입은 제네릭 타입을 사용하고 싶으나, 실 타입 매개변수를 모르거나, 어떤 타입이든 관계없다면
타입 대신 ? 를 사용하는 것이다.
List<?> 는 모든 종류의 List 를 받는다.
기존 원천 타입과 무슨 차이냐고?
? 로 표시된 녀석에는 null 이 아닌 어떤 타입도 마음대로 추가할 수 없다.
즉 reaonly 처럼 작동한다.
-
바운드 와일드 카드 타입은 ? extends, ? super 등의 조건을 주어 ? 를 한정지을 수 있다.
-
런타임 시에는 제네릭 타입의 정보가 없어진다.
-
새 코드에는 원천 타입을 사용하지 않는다는 규칙에 두 가지 예외가 있다.
그 이유는 런타임 시에는 제네릭 타입 정보가 없어진다는 것 때문에 발생한다.
1. 원천 타입은 클래스 리터럴(class literal) 형태로 사용해야 한다.
원천 타입을 매개변수화 타입과 사용할 수 없다.(배열 타입과 기본형 타입은 가능)
즉, List.class. String[].class, int.class 는 적합하지만, List<String>.class, List<?>.class 는 불가능하다.
2. 언바운드 와일드 카드 타입이 아닌 매개변수화 타입에 대해 instanceof 연산자를 사용할 수 없다.
제네릭 타입과 함께 instanceof 연산자를 사용할 때는 다음과 같이 하는 것이 좋다.
if ( o instanceof Set ){ // 원천 타입
Set<?> m = (Set<?>) o; // 언바운드 와일드 카드 타입
...
}
Summary
원천 타입을 사용하면 런타임 시 예외가 생길 수 있으므로 앞으로 새 코드에는 사용하지 말자.
원천 타입을 아직 사용할 수 있는 이유는 기존 코드와의 상호 호환성, 운용성 때문일 때 만이다.
Set<Object>는 매개변수화 타입으로써 어떤 객체도 포함할 수 있는 Set 이고, Set<?>는 언바운드 와일드 타입이다.
Set 은 원천 타입으로 타입 안전이 보장되지 않는다.
!!! 에러는 가능한 빨리, 최고는 컴파일 시점에 발견하는 것이 가장 좋다.
'프로그래밍 놀이터 > 디자인 패턴, 리펙토링' 카테고리의 다른 글
[Effective Java] 컴파일 경고 메세지가 없게 하자. (0) | 2016.11.24 |
---|---|
[Effective Java] 타입 안전이 보장되는 혼성(heterogeneous) 컨테이너의 사용을 고려하자. (0) | 2016.11.22 |
[Effective Java] static 맴버 클래스를 많이 사용하자. (0) | 2016.11.17 |
[Effective Java] 전략을 표현할 때 함수 객체를 사용하자. (0) | 2016.11.15 |
[Effective Java] 태그(tagged) 클래스보다는 클래스 계층을 사용하자. (0) | 2016.11.14 |
댓글