source

Java에서의 범용 삭제의 개념은 무엇입니까?

gigabyte 2022. 8. 16. 23:31
반응형

Java에서의 범용 삭제의 개념은 무엇입니까?

Java에서의 범용 삭제의 개념은 무엇입니까?

이는 기본적으로 컴파일러 속임수를 통해 Java에서 제네릭스를 구현하는 방법입니다.컴파일된 범용 코드는 실제로java.lang.ObjectT(또는 기타 타입 파라미터) - 컴파일러에 실제로 범용 타입임을 알려주는 메타데이터가 있습니다.

메서드에 몇 를 파악합니다( " 인수" for " argument for "type").T컴파일 시에 올바른 작업을 하고 있는지 검증합니다만, 송신된 코드는, 다음과 같이 말하고 있습니다.java.lang.Object에 따라 - 추가 캐스트를 생성합니다. 시, " " " " 입니다.List<String> a. a. a.List<Date>컴파일러에 의해 추가 유형 정보가 지워졌습니다.

들어 시 에는 "C#"과 같은 할 수 .typeof(T), 이 말은 '이렇게 하다'에 합니다.T.class- 후자가 무효라는 점만 제외하고.(간에는 그 이상의 차이가 있습니다.NET Java net net net net net net 。유형 삭제는 Java 제네릭을 다룰 때 많은 "홀수" 경고/오류 메시지의 소스입니다.

기타 자원:

한편, 컴파일러가 소거를 실행할 때 무엇을 하고 있는지를 실제로 확인하는 것은 흥미로운 연습입니다.전체 개념을 조금 이해하기 쉽게 합니다.컴파일러를 통해 제네릭을 지우고 캐스트를 삽입한 Java 파일을 출력할 수 있는 특수한 플래그가 있습니다.예:

javac -XD-printflat -d output_dir SomeFile.java

-printflat더(the-XD는 '알려주는 것입니다.javac 컴파일을 하는 것이 한다.javac는, 「」 」의 「 」 。-d output_dir컴파일러가 새로운 .disc 파일을 저장할 장소가 필요하기 때문에 필요합니다.

물론 이는 단순히 삭제만 하는 것이 아닙니다.컴파일러의 모든 자동 작업은 여기서 수행됩니다.를 들어되어 있습니다. 스타일의 foreach가 삽입되어 .for 루프로 됩니다.for루프 등작은 일들이 자동으로 일어나는 것을 볼 수 있어서 좋다.

소거(Erasure)는 문자 그대로 소스 코드에 있는 유형 정보가 컴파일된 바이트 코드에서 지워지는 것을 의미합니다.몇 가지 코드로 이것을 이해합시다.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class GenericsErasure {
    public static void main(String args[]) {
        List<String> list = new ArrayList<String>();
        list.add("Hello");
        Iterator<String> iter = list.iterator();
        while(iter.hasNext()) {
            String s = iter.next();
            System.out.println(s);
        }
    }
}

이 코드를 컴파일한 후 Java 디컴파일러로 디컴파일하면 다음과 같은 결과를 얻을 수 있습니다.디컴파일된 코드에는 원래 소스 코드에 있는 유형 정보의 트레이스가 포함되어 있지 않습니다.

import java.io.PrintStream;
import java.util.*;

public class GenericsErasure
{

    public GenericsErasure()
    {
    }

    public static void main(String args[])
    {
        List list = new ArrayList();
        list.add("Hello");
        String s;
        for(Iterator iter = list.iterator(); iter.hasNext(); System.out.println(s))
            s = (String)iter.next();

    }
} 

이미 매우 완전한 Jon Sket의 답변을 완성하기 위해서는 유형 삭제개념이 이전 버전의 Java와의 호환성 필요성에서 비롯되었음을 깨달아야 합니다.

Eclipse Con 2007(더 이상 제공되지 않음)에서 처음 소개된 호환성에는 다음과 같은 사항이 포함되어 있습니다.

  • 소스 호환성(반드시...)
  • 바이너리 호환성(필요!)
  • 이행 호환성
    • 기존 프로그램은 계속 작동해야 합니다.
    • 기존 라이브러리는 일반 형식을 사용할 수 있어야 합니다.
    • 그랬을 거야!

원답:

이 때문에,

new ArrayList<String>() => new ArrayList()

더 큰 재검증을 위한 제안들이 있다."추상적 개념을 현실로 간주한다"는 것을 재확인합니다.여기서 언어 구성은 구문설탕이 아니라 개념이어야 합니다.

Java 6의 메서드도 언급해야 합니다.Java 6은 지정된 컬렉션의 역동적인 타이프세이프 뷰를 반환합니다.잘못된 유형의 요소를 삽입하려고 하면 즉시 발생합니다.ClassCastException.

언어의 제네릭메커니즘은 컴파일 타임(정적) 타입 체크를 제공하지만 체크되지 않은 캐스트를 사용하면 이 메커니즘을 무효화할 수 있습니다.

컴파일러는 이러한 체크되지 않은 모든 조작에 대해 경고를 발행하므로 보통 이것은 문제가 되지 않습니다.

단, 다음과 같이 스태틱타입 체크만으로는 불충분한 경우가 있습니다.

  • 컬렉션이 서드파티 라이브러리에 전달되고 라이브러리 코드가 잘못된 유형의 요소를 삽입하여 컬렉션을 손상시키지 않도록 해야 합니다.
  • ClassCastException이는 잘못 입력된 요소가 파라미터화된 컬렉션에 포함되었음을 나타냅니다.안타깝게도 이 예외는 잘못된 요소가 삽입된 후 언제든지 발생할 수 있으므로 일반적으로 문제의 실제 원인에 대한 정보가 거의 또는 전혀 제공되지 않습니다.

거의 4년 후인 2012년 7월 업데이트:

현재(2012년)에 대해서는 "API 이행 호환성 규칙(서명 테스트)"에 자세히 기재되어 있습니다.

Java 프로그래밍 언어는 삭제를 사용하여 제네릭을 구현합니다.이것에 의해, 타입에 관한 몇개의 보조 정보를 제외하고, 레거시 버전과 범용 버전이 같은 클래스 파일을 생성할 수 있습니다.클라이언트 코드를 변경하거나 다시 컴파일하지 않고 레거시 클래스 파일을 일반 클래스 파일로 바꿀 수 있으므로 이진 호환성은 손상되지 않습니다.

일반적이지 않은 레거시 코드와의 인터페이스를 용이하게 하기 위해 파라미터화된 유형의 삭제를 유형으로 사용할 수도 있습니다.이러한 유형을 원시 유형(Java Language Specification 3/4.8)이라고 합니다.원시 유형을 허용하면 소스 코드의 하위 호환성도 보장됩니다.

이에 따르면 다음 버전의 Version은java.util.Iterator클래스는 바이너리 코드와 소스 코드 모두 하위 호환성이 있습니다.

Class java.util.Iterator as it is defined in Java SE version 1.4:

public interface Iterator {
    boolean hasNext();
    Object next();
    void remove();
}

Class java.util.Iterator as it is defined in Java SE version 5.0:

public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove();
}

이미 완성된 Jon Sket의 답변을 보완합니다.

에 의한 은, 의 귀찮은 를 들면, no no no name)을.new T[42])이렇게 하는 주된 이유는 바이트 코드의 하위 호환성이었다고도 언급되어 있습니다.이것 또한 대부분 사실이다.생성된 -target 1.5 바이트코드는 단순한 탈당 주조 -target 1.4와는 다소 다르다.엄밀히 말하면, 런타임에 범용 타입의 인스턴스화에 액세스 할 수 있어 바이트 코드에 실제로 무엇인가 있는 것을 증명합니다.

더 흥미로운 점은 (아직 제기되지 않은) 삭제 기능을 사용하여 제네릭스를 구현하면 고급 유형 시스템이 달성할 수 있는 작업에 훨씬 더 많은 유연성을 제공한다는 것입니다.공용 언어 런타임과 이것의 좋은 예는 스칼라의 JVM구현입니다.는 JVM에, 그것은 higher-kinds 직접 사실은 자바 가상 머신 지원 자체가 제네릭 형식(이"종류"효과적으로 결석한 이후)에 대한 제한을 가할 예정을 구현하는 것이 가능하다.이것은 CLR,는 매개 변수를 예시의 런타임 지식과 대조된다.이것 때문에 공용 언어 런타임 자체 어떻게 일반 명의 약을 사용한 시도가 예기치 않은 규칙을 가지고 시스템을 연장할 무효화 사용되어야 한다의 개념을 가져야 한다.결과적으로, 공용 언어 런타임에 스칼라의 higher-kinds, 그들 plain-old과not-entirely-compatible를 만들고 삭제를 이상한 형태는 컴파일러 자체 내에서 모방을 사용 시행하고 있다.NET 일반 명의 약.

런타임에 장난스러운 일을 하고 싶을 때는 삭제가 불편할 수 있지만 컴파일러 라이터에게 가장 유연성이 있습니다.그래서 금방이라도 사라지지 않는 것 같아요

제가 알기로는 (가 되는 것)NET guy) JVM에는 범용 개념이 없기 때문에 컴파일러는 타입 파라미터를 오브젝트로 대체하고 모든 캐스팅을 수행합니다.

즉, Java 제네릭은 구문설탕에 불과하며 참조에 의해 전달될 때 박스/언박스를 필요로 하는 값 유형에 대해 성능 향상을 제공하지 않습니다.

좋은 설명들이 있다.디컴파일러에서 타입 소거가 어떻게 동작하는지를 나타내는 예만을 추가합니다.

오리지널 클래스,

import java.util.ArrayList;
import java.util.List;


public class S<T> {

    T obj; 

    S(T o) {
        obj = o;
    }

    T getob() {
        return obj;
    }

    public static void main(String args[]) {
        List<String> list = new ArrayList<>();
        list.add("Hello");

        // for-each
        for(String s : list) {
            String temp = s;
            System.out.println(temp);
        }

        // stream
        list.forEach(System.out::println);
    }
}

바이트 코드에서 디컴파일된 코드,

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.Consumer;

public class S {

   Object obj;


   S(Object var1) {
      this.obj = var1;
   }

   Object getob() {
      return this.obj;
   }

   public static void main(String[] var0) {

   ArrayList var1 = new ArrayList();
   var1.add("Hello");


   // for-each
   Iterator iterator = var1.iterator();

   while (iterator.hasNext()) {
         String string;
         String string2 = string = (String)iterator.next();
         System.out.println(string2);
   }


   // stream
   PrintStream printStream = System.out;
   Objects.requireNonNull(printStream);
   var1.forEach(printStream::println);


   }
}

언급URL : https://stackoverflow.com/questions/313584/what-is-the-concept-of-erasure-in-generics-in-java

반응형