![](https://velog.velcdn.com/images/yeomyaloo/post/9cb2297b-54b0-4dc2-bb25-ee82b6e6e457/image.png)
제네릭
[아이템 26. 로(raw) 타입은 사용하지 말라]
- 제네릭이 무엇인지를 알아보고 로타입이 무엇인지를 알아보자
[핵심 정리]
- 제네릭을 도입하는 도중 이를 잘 적응시키기 위해서 로타입을 만들었다.
- 그러나 로 타입은 리터럴을 사용하는 경우가 아니라면 사용하지 말자
[용어 정리]
1. 클래스와 인터페이스 선언에 타입 매개변수 사용
- 클래스나 인터페이스 선언 시에 타입 매개변수를 사용하면 제네릭 클래스, 제네릭 인터페이스가 된다.
1-1. 클래스 선언에 타입 매개변수 사용한 경우
public class ClassName<T>{ ... }
1-2. 인터페이스 선언에 타입 매개변수를 사용한 경우
public interface InterfaceName<T>{ ... }
2. 타입 파라미터를 가지고 인터페이스, 클래스를 선언하는 이유
- 어떤 종류의 객체든지 저장할 수 있기 때문이다.
- 또한 타입 변환의 문제를 막을 수 있기 때문이다.
[로 타입 (raw type)]
- 제네릭 타입을 하나 정의하면 그에 딸린 로타입도 함께 정의된다.
1. 로 타입이란?
- 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않은 경우 로 타입이라 한다.
List
:는 로타입에 해당한다.
List<String>
:은 제네릭 타입에 해당한다.
- 로 타입은 제네릭 정보가 전부 지워진 것처럼 동작한다.
- 로 타입은 제네릭이 도입되기 전의 코드와 도입된 후의 코드가 호환이 잘 되게 하기 위한 방법 중 하나다.
2. 로 타입의 예시 코드
private final Collection stamps =...;
stamps.add(new Coin(...));
- 해당 코드는 컴파일러가 모호한 경고 메시지를 보여주기만 할 뿐 객체를 꺼내서 사용하지 않는한 문제가 되지 않는다.
- 그러나 객체를 꺼내 사용하게 된다면 컴파일러 측에서 잡아낼 수 있던 에러도 런타임에 문제를 겪는 코드가 될수 있기 때문에 가능하면 컴파일시에 해당 오류를 잡아내는 것이 좋다.
3. 로 타입 말고 매개변수화된 컬렉션 타입 사용 코드
private final Collection<Stamp> stamps =...;
- 해당 작업을 진행함으로서 해당 컬렉션에는 Stamp 객체만 넣어야 함을 컴파일러가 인지하게 된다.
- 따라서 아무 경고 없이 컴파일되는 경우라면 의도대로 동작한 것임을 보장하게 되는 것이다.
- 타입 매개변수를 사용하여 정의한 것에 다른 타입의 데이터를 넣으려 하면 컴파일 오류가 발생한다.
4. 왜 로 타입을 막아두지 않았을까?
- 로 타입을 사용하지 않아야 한다면서 왜 로 타입 사용을 막아두지 않았을까?
- 자바가 제네릭을 받아들이기까지 10년이 걸렸는데 기존 코드를 수용하면서 제네릭 코드와도 함께 동작할 수 있게 해야 했기 때문이다.
- 마이그레이션 호환성을 위해서 로 타입을 지원하고 제네릭 구현에는 소거 방식을 사용하기도 했다.
5. List<Object>
와 로타입의 차이점
List<Object>
의 경우엔 임의의 객체를 모두 허용하는 매개변수화 타입이다.
- 이때 해당
List<Object>
의 경우엔 모든 타입을 허용한다고 컴파일러에게 알려주는 반면 로 타입의 경우엔 아예 발을 뺀 경우이기 때문에 List<Object>
는 사용이 가능하다.
6. 그러나 List<Object>
는 List를 넘겨 받는 메서드에 사용할 수 없다.
- 제네릭의 하위 타입 규칙 때문인데,
List<String>
은 List의 하위 타입이지만, List<Object>
의 경우엔 List의 하위 타입이 아니기 때문이다.
7. 비한정 와일드 카드 타입
- 실제 매개변수가 무엇인지 신경 쓰고 싶지 않다면 물음표(?)를 사용하자.
Set<E>
의 비한정 와일드 카드 타입은 Set<?>
이다.
- 이 비한정 와일드 카드 타입은 어떤 타입이라도 담을 수 있는 가장 범용적인 매개변수화 타입이다.
7-1. Set
로 타입과 Set<?>
의 차이점?
- 로타입은 안전하지 않고 비한정 와일드 카드 타입은 안전하다.
[로타입을 사용해야 할 때]
1. class 리터럴에는 로 타입을 사용해야 한다.
- 자바 명세는 class 리터럴에 매개변수화 타입을 사용하지 못하게 되어 있다.
- 배열과 기본 타입은 허용한다.
2. instanceof 연산자에는 로 타입을 사용해야 한다.
- 런타임시에는 제네릭 정보가 지워지기 때문에 instanceof 연산자는 비한정적 와일드카드 타입 이외의 매개변수화 타입에는 적용할 수 없다.
- 로 타입이든 비한정적 와일드카드 타입이든 instanceof에서는 완전히 똑같이 동작한다. 그래서 List<매개변수화타입>을 작성해서 코드를 써내려가는 건 코드를 길고 지저분하게 만드는 일이라 그냥 로 타입을 사용하는게 낫다.