java-squid/effective-java

[아이템 26] 로 타입은 사용하지 말라

Closed this issue · 6 comments

[아이템 26] 로 타입은 사용하지 말라

p159 ..런타임에는 제네릭 타입 정보가 지워지므로....

약간 advanced한 질문으로 생각됩니다.
런타임에는 왜 제네릭 정보가 지워지는 걸까요?

한번 알아보면 좋을 것 같습니다

@102092

p159 ..런타임에는 제네릭 타입 정보가 지워지므로....

약간 advanced한 질문으로 생각됩니다.
런타임에는 왜 제네릭 정보가 지워지는 걸까요?

한번 알아보면 좋을 것 같습니다

  • Why?
    • 파고 들어가자면 밑도 끝도 없이 어려운 주제...
    • Joshua Bloch이 언급한 이유는 Java 5 이전에 존재하던 raw type에 대한 하위 호완성을 유지하기 위함.
      • e.g. List l = new ArrayList();를 컴파일 에러로 취급하지 않고 경고만 하고 넘어가기.
  • What / How?
    • Type Erasure?
      • 컴파일 전

          public class Node<T> {
        
              private T data;
              private Node<T> next;
        
              public Node(T data, Node<T> next) {
                  this.data = data;
                  this.next = next;
              }
        
              public T getData() { return data; }
              // ...
          }
        
      • Type erasure 후 (컴파일 중)

          public class Node {
        
             private Object data;
             private Node next;
        
              public Node(Object data, Node next) {
                  this.data = data;
                  this.next = next;
              }
        
              public Object getData() { return data; }
              // ...
          }
        
      • type paramter TObject로 바뀌어있는 것을 확인할 수 있다.

      • 더 자세한 내용은 Erasure of Generic Types

  • Collection<Supertype>Collection<Subtype>의 상위 클래스가 아니다!
    • 왜? Collection<Animal>Collection<Dog>의 상위 클래스면 Collection<Dog>Cat을 추가할 수 있게 된다...
    // Illegal code - because otherwise life would be Bad
    List<Dog> dogs = new ArrayList<Dog>(); // ArrayList implements List
    List<Animal> animals = dogs; // Awooga awooga
    animals.add(new Cat());
    Dog dog = dogs.get(0); // This should be safe, right?
  • 에러 예시
    class A { /* ... */ }
    class B extends A { /* ... */ }
    B b = new B();
    A a = b;
    List<B> lb = new ArrayList<>();
    List<A> la = lb;   // compile-time error
  • 그렇기 때문에 와일드카드를 써야한다.
    void f(Set<?> s) {}
    void g(Set<Object> s) {}
    Set<String> s = new HashSet<>();
    f(s);
    g(s); // compile-time error
  • 더 자세한 내용은: Wildcards and Subtyping

@david215 제가 질문했던 내용이 Item28에 나오는 군요...

@102092 아이템 26부터 30번까지 공부해보니 겹치는게 많습니다. 겹치는 부분은 해당 이슈와 링크걸어 이해하기 쉽게 하는것도 나쁘지않을듯 합니다.

자바봄의 자바의 제네릭
https://javabom.tistory.com/69?category=835783
Java 컴파일러의 타입 소거

  • 제네릭 타입( Example) 에서는 해당하는 타입 파라미터 (T) 나 Object로 변경해준다.
  • Object로 변경하는 경우는 unbounded 된 경우를 뜻하며, 이는 <E extends Comparable>와 같이 bound를 해주지 않은 경우를 의미한다.
    따라서 이 소거 규칙에 대한 바이트코드는 제네릭을 적용할 수 있는 일반 클래스, 인터페이스, 메서드에만 해당된다.
  • 타입 안정성 보존을 위해 필요하다면 type casting을 넣어준다.
  • 확장된 제네릭 타입에서 다형성을 보존하기 위해 bridege method를 생성한다.