List orders = new ArrayList(); // raw type
orders.add(new Order());
Order o = (Order) orders.get(0);raw type 은 제네릭 검사를 완전히 꺼버립니다. 경고(unchecked)가 나지만 컴파일은 되기 때문에 놓치기 쉽고, 다른 곳에서 엉뚱한 타입이 들어와도 get 하는 순간까지 아무도 모릅니다. raw type 이 남아 있는 이유는 오직 JDK 1.4 이전 코드와의 호환뿐입니다.
✅
List<Order> orders = new ArrayList<>();
orders.add(new Order());
Order o = orders.get(0);List<Dog> 를 List<Animal> 에 대입하려고 함List<Dog> dogs = new ArrayList<>();
List<Animal> animals = dogs; // 컴파일 에러: incompatible types제네릭은 불공변입니다(2.6). 허용하면 animals.add(new Cat()) 으로 dogs 가 오염됩니다. "읽기만 할 것"이라면 와일드카드로 의도를 표현하세요.
✅
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs; // 읽기 전용 뷰
for (Animal a : animals) a.sound();? extends 리스트에 add 시도static void addDefaults(List<? extends Number> nums) {
nums.add(0); // 컴파일 에러: List<capture of ? extends Number>
}? extends Number 는 "Number 의 어떤 하위 타입인지 모름"이므로 넣을 수 없습니다. 값을 넣는 파라미터(consumer)는 super 여야 합니다(PECS).
✅
static void addDefaults(List<? super Integer> nums) {
nums.add(0); // OK: Integer 의 상위 타입 리스트에는 Integer 를 넣을 수 있음
}static <T> T[] toArray(T... items) {
T[] copy = new T[items.length]; // 컴파일 에러: generic array creation
return copy;
}타입 소거 때문에 T[] 를 만들 수 없습니다. List<T> 를 반환하거나 Class<T> 토큰 또는 Arrays.copyOf 를 사용하세요.
✅
static <T> List<T> toList(T... items) { return new ArrayList<>(Arrays.asList(items)); }
// 또는
static <T> T[] copy(T[] src) { return Arrays.copyOf(src, src.length); } // src 의 런타임 타입을 재사용class Cache<T> {
private static T lastValue; // 컴파일 에러: non-static type variable T cannot be referenced from a static context
}static 필드는 클래스당 하나인데, Cache<String> 과 Cache<Integer> 는 소거 후 같은 클래스입니다. 하나의 필드가 두 타입을 동시에 가질 수는 없습니다. static 메서드는 자기 자신의 타입 파라미터를 따로 선언하면 됩니다.
✅
class Cache<T> {
private T lastValue; // 인스턴스 필드
static <U> Cache<U> of(U initial) { // 메서드 자체의 타입 파라미터 U
Cache<U> c = new Cache<>(); c.lastValue = initial; return c;
}
}static List<? extends Number> numbers() { ... }
List<? extends Number> ns = numbers();
ns.add(1); // 호출자가 add 못 함 — 사용성 최악와일드카드는 파라미터의 유연성을 위한 도구입니다. 반환 타입에 쓰면 호출자가 그 유연성의 대가(제약)를 떠안게 됩니다.
✅
static List<Number> numbers() { ... } // 또는 <T extends Number> List<T>