자바 범용 지우 기

9320 단어
레 퍼 런 스
The Java™ Tutorials http://www.baeldung.com/java-type-erasure
범용 지우 기
  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
  • Insert type casts if necessary to preserve type safety.
  • Generate bridge methods to preserve polymorphism in extended generic types.

  • Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.
    만약 에 범 형 매개 변수 가 경계 가 있다 면 컴 파일 한 후에 경계 로 바 뀔 것 입 니 다. 그렇지 않 으 면 Object 로 바 뀔 것 입 니 다. 필요 한 전환 작업 을 삽입 합 니 다. 범 형 류 를 계승 하 는 클래스 에 있어 컴 파일 러 는 브리지 방법 bridge methods 을 추가 하여 다 중 태 를 유지 할 것 입 니 다. 컴 파일 한 후에 새로운 클래스 가 생 성 되 지 않 았 기 때문에 범 형 운행 시 추가 비용 을 도입 하지 않 았 습 니 다.
    예시
    During the type erasure process, the Java compiler erases all type parameters and replaces each with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded.
    위의 replaces each with its first bound 는 아직 연구 가 필요 합 니 다. 개인 적 인 이 해 는 이러한 상황 에서 일반적인 유형 이 First 로 바 뀌 었 다 는 것 입 니 다. 클 라 스 파일 을 역 컴 파일 하여 검증 하려 고 했 는데 Java1.8 컴 파일 된 클 라 스 파일 을 역 컴 파일 한 후에 범 형 매개 변 수 를 보 았 습 니 다. 아이디어 자체 의 역 컴 파일 도 구 를 사용 하여 클 라 스 파일 을 역 컴 파일 하 는 것 에 대해 서 는...범 형 유형의 원인 을 볼 수 있 습 니 다. 다음 과 같은 몇 편의 글 을 참고 할 수 있 습 니 다. 이 글 을 잘 썼 는 지 아 시 겠 습 니까? 추천 합 니 다. 자바 범 형 지우 기 는 어느 단계 에서 발생 하 는 지, 어떻게 반 컴 파일 도구 로 범 형 지우 기 후의 코드 를 볼 수 있 습 니까?java - generic - types - type - erasure java - type - erasure - Why - can - i - see - the - type - when - i - look - at - the - bytecode. 문장 은 마지막 으로 몇 개의 역 컴 파일 된 예 를 썼 습 니 다. 본문 마지막 에 볼 수 있 습 니 다.
    무한 범 형 매개 변수
    public class Node {
    
        private T data;
        private Node next;
    
        public Node(T data, Node next) {
            this.data = data;
            this.next = next;
        }
    
        public T getData() { return data; }
        // ...
    }
    

    무한 이기 때문에 유형 매개 변 수 는 직접 Object 로 바 뀌 었 습 니 다. 컴 파일 후:
    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; }
        // ...
    }
    

    유 계 범 형 매개 변수
    public class Node> {
    
        private T data;
        private Node next;
    
        public Node(T data, Node next) {
            this.data = data;
            this.next = next;
        }
    
        public T getData() { return data; }
        // ...
    }
    

    한 정 된 경계 가 있 기 때문에 바로 Comparable 로 바 뀌 었 습 니 다. 코드 는 다음 과 같 습 니 다.
    public class Node {
    
        private Comparable data;
        private Node next;
    
        public Node(Comparable data, Node next) {
            this.data = data;
            this.next = next;
        }
    
        public Comparable getData() { return data; }
        // ...
    }
    

    일반적인 방법의 유형 지우 기
    무한 하 다
    // Counts the number of occurrences of elem in anArray.
    //
    public static  int count(T[] anArray, T elem) {
        int cnt = 0;
        for (T e : anArray)
            if (e.equals(elem))
                ++cnt;
            return cnt;
    }
    

    컴 파일 후:
    public static int count(Object[] anArray, Object elem) {
        int cnt = 0;
        for (Object e : anArray)
            if (e.equals(elem))
                ++cnt;
            return cnt;
    }
    

    경계 가 있다
    class Shape { /* ... */ }
    class Circle extends Shape { /* ... */ }
    class Rectangle extends Shape { /* ... */ }
    

    일반적인 방법:
    public static  void draw(T shape) { /* ... */ }
    

    컴 파일 후:
    public static void draw(Shape shape) { /* ... */ }
    

    유형 지우 기 영향 및 브리지 방법
    다음 두 가 지 를 고려 하 다
    public class Node {
    
        public T data;
    
        public Node(T data) { this.data = data; }
    
        public void setData(T data) {
            System.out.println("Node.setData");
            this.data = data;
        }
    }
    

    범 형 류 에 계승:
    public class MyNode extends Node {
        public MyNode(Integer data) { super(data); }
    
        public void setData(Integer data) {
            System.out.println("MyNode.setData");
            super.setData(data);
        }
    }
    

    호출 상황:
    MyNode mn = new MyNode(5);
    Node n = mn;            // A raw type - compiler throws an unchecked warning
    n.setData("Hello");     
    Integer x = mn.data;    // Causes a ClassCastException to be thrown.
    

    형식 지우 기 후의 코드:
    MyNode mn = new MyNode(5);
    Node n = (MyNode)mn;         // A raw type - compiler throws an unchecked warning
    n.setData("Hello");
    Integer x = (String)mn.data; // Causes a ClassCastException to be thrown.
    

    해석:
  • n.setData("Hello"); causes the method setData(Object) to be executed on the object of class MyNode. (The MyNode class inherited setData(Object) from Node.)
  • In the body of setData(Object), the data field of the object referenced by n is assigned to a String.
  • The data field of that same object, referenced via mn, can be accessed and is expected to be an integer (since mn is a MyNode which is a Node.
  • Trying to assign a String to an Integer causes a ClassCastException from a cast inserted at the assignment by a Java compiler.

  • 브리지 방법
    유형 을 지 운 후에 위의 두 가지 유형 은 다음 과 같은 형식 으로 변 한다.
    public class Node {
    
        public Object data;
    
        public Node(Object data) { this.data = data; }
    
        public void setData(Object data) {
            System.out.println("Node.setData");
            this.data = data;
        }
    }
    
    public class MyNode extends Node {
    
        public MyNode(Integer data) { super(data); }
    
        public void setData(Integer data) {
            System.out.println("MyNode.setData");
            super.setData(data);
        }
    }
    

    두 가지 방법 setData 을 볼 수 있 습 니 다. 사실은 Override 의 요 구 를 만족 시 키 지 못 합 니 다. 매개 변수 유형 이 다 르 기 때 문 입 니 다. 이 문 제 를 해결 하기 위해 컴 파일 러 는 브리지 방법 을 만들어 다 형 을 유지 합 니 다.
    class MyNode extends Node {
    
        // Bridge method generated by the compiler
        //
        public void setData(Object data) {
            setData((Integer) data);
        }
    
        public void setData(Integer data) {
            System.out.println("MyNode.setData");
            super.setData(data);
        }
    
        // ...
    }
    

    javap 역 컴 파일 을 사용 하여 일반적인 형식 지우 기 예 를 봅 니 다.
    아래 이 단락 에 대한 검증.
    During the type erasure process, the Java compiler erases all type parameters and replace each with its first bound if the type parameter is bounded. 두 개의 인터페이스 AB:
    package generictopic.typeerasure;
    /**
     * Created by xiaofu on 17-11-7.
     */
    public interface A {
        void a();
    }
    
    package generictopic.typeerasure;
    
    /**
     * Created by xiaofu on 17-11-7.
     */
    public interface B {
        void B();
    }
    

    클래스 FirstBoundA, 실현 AB 인터페이스, 그리고 A 앞 에 쓰기:
    package generictopic.typeerasure;
    
    /**
     * Created by xiaofu on 17-11-7.
     */
    public class FirstBoundA {
    
        public void test(T item){
            System.out.println(item);
        }
    
    }
    

    클래스 FirstBoundB, 실현 AB 인터페이스, 그리고 B 앞 에 쓰기:
    package generictopic.typeerasure;
    
    /**
     * Created by xiaofu on 17-11-7.
     */
    public class FirstBoundB  {
    
        public void test(T item){
            System.out.println(item);
        }
    
    }
    

    이 몇 개의 파일 을 컴 파일 한 다음 에 각각 javap 으로 역 컴 파일 합 니 다. 자바 p 인 자 는 간단 하기 위해 -s 인 자 를 직접 사용 합 니 다. 즉 Prints internal type signatures.FirstBoundA.class 에 대해 역 컴 파일 작업 을 수행 합 니 다.
    javap -s FirstBoundA.class 
    
    test 방법 을 볼 수 있 습 니 다. descriptor 부분 은 Lgenerictopic/typeerasure/A;, 즉 범 형 유형 이 첫 번 째 경계 A 로 바 뀌 었 습 니 다.
    Compiled from "FirstBoundA.java"
    public class generictopic.typeerasure.FirstBoundA {
      public generictopic.typeerasure.FirstBoundA();
        descriptor: ()V
    
      public void test(T);
        descriptor: (Lgenerictopic/typeerasure/A;)V
    }
    

    다시 FirstBoundB.class 에 대한 역 컴 파일 결 과 를 볼 수 있 습 니 다. 매개 변 수 는 첫 번 째 경계 B 로 바 뀌 었 습 니 다.
    Compiled from "FirstBoundB.java"
    public class generictopic.typeerasure.FirstBoundB {
      public generictopic.typeerasure.FirstBoundB();
        descriptor: ()V
    
      public void test(T);
        descriptor: (Lgenerictopic/typeerasure/B;)V
    }
    

    따라서 특정한 범 형 매개 변수 가 여러 개의 경계 가 있 을 때 컴 파일 러 의 방법 은 유형 을 첫 번 째 경계 로 바 꾸 는 것 이다. 그러나 이 유형의 매개 변 수 는 여러 개의 경계 가 있 고 그 중 하 나 는 class 이 라면 반드시 첫 번 째 에 써 야 한다. 이것 은 문법 이 요구 하 는 것 이다.

    좋은 웹페이지 즐겨찾기