Java 유형 삭제의 이점은 무엇입니까?
오늘 트윗을 읽었는데
자바 사용자들이 잘못된 것은 무시하고 자바가 유일하게 맞힌 활자 삭제에 대해 불평하는 것은 우스운 일이다.
제 질문은 다음과 같습니다.
Java의 Type Erasure에는 어떤 이점이 있습니까?하위 호환성 및 런타임 성능에 대한 JVM 구현 선호 외에 기술 또는 프로그래밍 스타일의 이점은 무엇입니까?
유형 삭제는 정상입니다.
사실대로 말하자
지금까지의 많은 답변들은 트위터 사용자에 대해 지나치게 관심을 가지고 있다.메신저가 아닌 메시지에 집중하는 것이 도움이 됩니다.지금까지 언급한 발췌문만 봐도 꽤 일관된 메시지가 있습니다.
자바 사용자들이 잘못된 것은 무시하고 자바가 유일하게 맞힌 활자 삭제에 대해 불평하는 것은 우스운 일이다.
막대한 이점(파라메트릭 등)과 비용(상상의 한계)이 없습니다.
새로운 T는 고장난 프로그램입니다.그것은 "모든 명제는 진실이다"라는 주장과 동형이다.난 이 일에 별로 관심이 없어.
목표: 합리적인 프로그램
이 트윗들은 우리가 기계를 작동시킬 수 있는지 아닌, 기계가 실제로 우리가 원하는 것을 할 것이라고 추론할 수 있는지에 관심이 있는 관점을 반영하고 있다.좋은 추리가 증거다.증명은 형식적인 표기법이나 형식적이지 않은 것으로 지정할 수 있습니다.사양 언어에 관계없이 명확하고 엄격해야 합니다.비공식 사양이 올바르게 구성되는 것이 불가능한 것은 아니지만, 실용적인 프로그래밍에 결함이 있는 경우가 많습니다.우리는 비공식적인 추론의 문제점을 보완하기 위해 자동화된 탐색 테스트와 같은 교정 조치를 취합니다.이것은 테스트가 본질적으로 나쁜 생각이라고 말하는 것은 아니지만, 인용된 트위터 사용자는 훨씬 더 나은 방법이 있다고 제안하고 있다.
그래서 우리의 목표는 기계가 실제로 프로그램을 실행하는 방법에 맞게 명확하고 엄격하게 추론할 수 있는 올바른 프로그램을 만드는 것입니다.하지만, 이것이 유일한 목표는 아니다.우리는 또한 우리의 논리가 어느 정도의 표현력을 갖기를 원합니다.예를 들어, 명제 논리로 표현할 수 있는 것은 한정되어 있습니다.1차 논리 같은 것에서 보편적())과 실존적())의 수량을 갖는 것은 좋다.
추론을 위한 유형 시스템 사용
이러한 목표는 유형 시스템에 의해 매우 적절하게 처리될 수 있습니다.이것은 Curry-Howard의 대응관계 때문에 특히 명확하다.이 대응관계는 종종 다음과 같은 비유로 표현된다.타입과 프로그램은 이론과 증명과 같다.
이 대응은 다소 심오하다.우리는 논리적인 표현을 취해서 그것을 유형별로 대응시켜 번역할 수 있다.컴파일 하는 것과 같은 타입의 시그니처를 가지는 프로그램이 있는 경우, 논리식이 보편적으로 참(동일어)인 것을 증명하고 있습니다.이것은 대응이 쌍방향이기 때문입니다.유형/프로그램과 정리/증명 세계 간의 변환은 기계적이고 많은 경우 자동화할 수 있습니다.
Curry-Howard는 프로그램 사양으로 우리가 하고 싶은 일에 잘 어울립니다.
자바에서는 타입 시스템이 유용합니까?
Curry-Howard에 대한 이해에도 불구하고, 어떤 사람들은 활자 시스템의 가치를 쉽게 무시하는 것을 발견합니다.
- 함께 일하는 것은 매우 어렵다
- (Curry-Howard를 통해) 표현력이 제한된 논리에 대응하는
- (시스템이 '약하다' 또는 '강하다'는 특성이 있음)가 파손되어 있습니다.
첫 번째 포인트는 아마도 IDE를 통해 Java의 타입 시스템을 쉽게 조작할 수 있을 것입니다(그것은 매우 주관적입니다).
두 번째 포인트는 자바가 1차 로직과 거의 일치합니다.제네릭스는 범용 정량화와 동등한 유형 시스템을 사용합니다.안타깝게도 와일드카드는 존재 수치의 극히 일부만 제공합니다.하지만 보편적 수량화는 꽤 좋은 시작이다.그런 기능을 할 수 있어서 좋았습니다.List<A>
A은(는) 완전히 제약이 없기 때문에 가능한 모든 목록에 대해 전체적으로 작동합니다.이것은 트위터 사용자가 말하는 "파라미터성"에 관한 것으로 이어진다.
파라메트릭성에 대해 자주 인용되는 논문은 Philip Wadler's Condems입니다.이 논문의 흥미로운 점은 활자 서명만으로 흥미로운 불변량을 증명할 수 있다는 것입니다.만약 우리가 이 불변량들에 대해 자동화된 테스트를 작성한다면 우리는 우리의 시간을 매우 낭비하게 될 것이다.예를 들어,List<A>
, 타입 시그니처만으로,flatten
<A> List<A> flatten(List<List<A>> nestedLists);
라고 추론할 수 있다
flatten(nestedList.map(l -> l.map(any_function)))
≡ flatten(nestList).map(any_function)
이것은 간단한 예이며, 아마 비공식적으로 추론할 수 있을 것입니다만, 이러한 증명은 형식 시스템으로부터 무료로 입수해, 컴파일러에 의해서 체크되는 것이, 한층 더 좋습니다.
지우지 않으면 악용될 수 있다
언어 구현의 관점에서, Java의 제네릭(유니버설 타입에 대응)은 우리의 프로그램이 하는 일에 대한 증거를 얻기 위해 사용되는 매개 변수에 매우 크게 관여합니다.이것은 언급된 세 번째 문제에 대한 것입니다.이러한 모든 입증과 정확성을 얻으려면 결함 없이 구현된 사운드 타입 시스템이 필요합니다.자바에는 분명히 우리의 논리를 무너뜨릴 수 있는 몇 가지 언어 특징이 있다.여기에는 다음이 포함됩니다.
- 외부 시스템과의 부작용
- 반사
소거되지 않은 제네릭스는 여러 면에서 반사와 관련이 있습니다.삭제하지 않고, 실장시에 전달되는 런타임 정보를 사용해 알고리즘을 설계할 때 사용할 수 있습니다.이것은 정적으로 우리가 프로그램에 대해 논할 때 전체상을 파악하지 못한다는 것을 의미합니다.반성은 우리가 정적으로 추론하는 증거의 정확성을 심각하게 위협한다.우연의 일치가 아니라 여러 가지 까다로운 결함으로 이어집니다.
그렇다면 지워지지 않는 제네릭이 "유용한" 방법은 무엇일까요?트윗에 기재되어 있는 사용법에 대해 생각해 봅시다.
<T> T broken { return new T(); }
T에 no-arg 컨스트럭터가 없으면 어떻게 됩니까?일부 언어에서는 아무것도 표시되지 않습니다.또는 null 값을 건너뛰고 예외 발생으로 바로 이동할 수도 있습니다(null 값이 원인이 되는 것 같습니다).우리의 언어는 튜링에 완전하기 때문에, 어떤 호출에 대한 추론은 불가능하다.broken
"안전한" 타입의 컨스트럭터와 그렇지 않은 컨스트럭터가 포함됩니다.우리의 프로그램이 보편적으로 작동한다는 확신을 잃었습니다.
지우는 것은 우리가 추론했다는 것을 의미합니다(그러니 지웁시다.
따라서 프로그램에 대해 논리를 세우고 싶다면 논리를 강하게 위협하는 언어 기능을 사용하지 말 것을 강력히 권장합니다.그러면 런타임에 유형을 삭제하면 어떨까요?필요 없어요.캐스트 실패가 발생하지 않거나 호출 시 방법이 누락될 수 있다는 만족감과 함께 효율성과 단순성을 얻을 수 있습니다.
지우는 것은 추론을 장려한다.
타입은 컴파일러가 프로그램의 정확성을 체크할 수 있도록 프로그램을 작성하는 데 사용되는 구조입니다.유형은 값에 대한 제안입니다. 컴파일러는 이 제안이 참임을 확인합니다.
프로그램 실행 중에는 타입 정보가 필요하지 않습니다.이 정보는 컴파일러에 의해 이미 확인되었습니다.컴파일러는 코드에 대한 최적화를 수행하기 위해 이 정보를 자유롭게 폐기할 수 있어야 합니다.코드가 더 빨리 실행되도록 하거나 더 작은 바이너리를 생성할 수 있습니다.유형 매개 변수를 삭제하면 이를 쉽게 수행할 수 있습니다.
Java는 유형 정보(반사, 인스턴스 등)를 런타임에 조회할 수 있도록 하여 정적 입력을 차단합니다.이를 통해 정적으로 검증할 수 없는 프로그램을 구성할 수 있습니다. 이 프로그램은 유형 시스템을 바이패스합니다.또한 정적 최적화의 기회도 놓치고 있다.
유형 매개 변수가 지워지면 이러한 잘못된 프로그램의 일부 인스턴스가 생성되지 않지만 더 많은 유형 정보가 지워지고 설비의 반사 및 인스턴스가 제거되면 더 이상의 잘못된 프로그램이 허용되지 않습니다.
삭제는 데이터 유형의 "모수성" 속성을 유지하는 데 중요합니다.컴포넌트 타입 T 위에 "List" 타입이 파라미터화되어 있다고 합니다.즉, List < T >이 유형은 이 목록 유형이 모든 유형 T에 대해 동일하게 작동한다는 제안입니다.T가 추상적이고 무제한적인 타입 파라미터라는 것은 우리가 이 타입에 대해 아무것도 모른다는 것을 의미하기 때문에 T의 특별한 경우에 대해 특별한 일을 할 수 없다는 것을 의미한다.
예를 들어 List xs = asList("3")가 있다고 가정합니다.xs.add("q") 요소를 추가합니다.[3], [q]로 끝납니다.이것은 파라메트릭이기 때문에 List xs = asList(7); xs.add(8)는 [7,8]로 끝나는 것으로 추측할 수 있습니다.String과 Int는 각각 1개씩 하지 않는 것을 타입으로 알 수 있습니다.
또한 List.add 함수는 T의 값을 갑자기 발명할 수 없는 것으로 알고 있습니다.asList("3")에 "7"이 추가된 경우 가능한 답변은 "3"과 "7" 값으로 구성된다는 것을 알고 있습니다.함수가 "2" 또는 "z"를 구성할 수 없기 때문에 목록에 추가될 가능성은 없습니다.이들 이외의 값은 추가해도 적절하지 않으며 파라미터성으로 인해 이러한 잘못된 프로그램이 생성되지 않습니다.
기본적으로, 소거 기능은 파라메트릭을 위반하는 수단을 방지하고, 따라서 정적 타이핑의 목표인 부정확한 프로그램의 가능성을 제거합니다.
(이미 여기에 답을 썼지만, 2년 후에 이 질문을 다시 보니 전혀 다른 답변 방법이 있다는 것을 깨달았기 때문에 이전 답변을 그대로 두고 이 답변을 추가합니다.)
Java Generics에서 수행된 프로세스가 "유형 삭제"라는 이름을 가질 자격이 있는지 여부는 매우 논쟁의 여지가 있습니다.범용 타입은 지워지지 않고 원시 타입으로 대체되므로 "타입 절단"이 더 나은 선택인 것 같습니다.
일반적으로 이해되는 유형 삭제의 본질적인 특징은 런타임이 액세스하는 데이터의 구조에 대해 "블라인드"되도록 함으로써 정적 유형 시스템의 경계 내에 있도록 강제하는 것입니다.이것에 의해, 컴파일러에 풀 파워가 주어져 정적 타입만을 기초로 한 정리법을 증명할 수 있습니다.또, 코드의 자유도를 제한해, 간단한 추론에 힘을 실어 줌으로써 프로그래머에게 도움이 됩니다.
Java의 유형 삭제는 이를 달성하지 못합니다.다음 예시와 같이 컴파일러에 장애가 발생합니다.
void doStuff(List<Integer> collection) {
}
void doStuff(List<String> collection) // ERROR: a method cannot have
// overloads which only differ in type parameters
(위의 2개의 선언은 소거 후 같은 메서드시그니처로 정리됩니다).
반대로 런타임은 객체의 유형과 그 이유를 검사할 수 있지만 삭제로 인해 True Type에 대한 통찰력이 저하되기 때문에 정적 유형 위반은 달성하기 어렵고 방지하기가 어렵습니다.
더 복잡하게 만들기 위해 원본 및 지워진 유형의 서명이 함께 존재하며 컴파일 시 병렬로 간주됩니다.이는 전체 프로세스가 런타임에서 유형 정보를 제거하는 것이 아니라 이전 버전과의 호환성을 유지하기 위해 일반 유형 시스템을 레거시 원시 유형 시스템으로 슈호핑하는 것이기 때문입니다.이 보석은 전형적인 예입니다.
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
(용장성extends Object
소거된 시그니처의 하위 호환성을 유지하기 위해 를 추가해야 합니다.)
이 점을 염두에 두고 견적서를 다시 살펴보겠습니다.
자바 사용자가 타입 삭제에 대해 불평하는 것은 재미있습니다.이것은 자바가 유일하게 옳게 한 것입니다.
Java는 정확히 무엇을 맞췄습니까?의미와 상관없이 단어 자체인가요?대조적으로, 겸손한 사람들을 보세요.int
type: 런타임 타입 체크는 전혀 실행되지 않으며 실행은 항상 완벽하게 타입 세이프합니다.올바른 방법으로 지우면 이렇게 됩니다.그게 있는지조차 알 수 없습니다.
여기서 전혀 고려되지 않은 것은 OOP의 런타임 다형성은 기본적으로 런타임의 유형 복제에 의존한다는 것입니다.참고된 유형에 의해 백본이 유지되는 언어가 유형 시스템에 큰 확장을 도입하고 유형 삭제에 기초할 때 인지 부조화는 불가피한 결과이다.이것이 바로 자바 커뮤니티에 일어난 일이다.그것이 바로 활자 삭제가 그렇게 많은 논란을 불러 일으킨 이유이며, 궁극적으로는 향후 자바 릴리즈에서 이를 취소할 계획이 있는 이유이다.자바 사용자들의 불만에서 재미있는 것을 발견하는 것은 자바 정신에 대한 솔직한 오해나 의식적으로 비방하는 농담을 드러낸다.
"Java가 제대로 된 것은 삭제뿐"이라는 주장은 "실행시 유형의 함수 인수에 대한 동적 디스패치에 기반한 모든 언어에는 근본적으로 결함이 있다"는 주장을 암시합니다.Java를 포함한 모든 OOP 언어에 대한 유효한 비판으로 간주될 수 있는 것은 확실하지만 런타임 다형성이 자명한 Java의 컨텍스트 내에서 기능을 평가하고 비판하는 중추적인 지점이 될 수는 없습니다.
요약하자면, "type erasure가 언어 디자인에서 가는 길"이라고 할 수 있지만, Java 내에서 type erasure를 지원하는 위치는 단순히 너무 늦었고, Oak가 Sun에 의해 채택되어 Java로 이름이 변경된 역사적 순간에도 이미 그렇게 되어 있었기 때문에 잘못되어 있습니다.
정적 타이핑 자체가 프로그래밍 언어 설계에서 적절한 방향인지에 대해서는 프로그래밍 활동을 구성하는 것으로 생각되는 훨씬 더 넓은 철학적 맥락에 들어맞습니다.수학의 고전적 전통에서 명백히 파생된 한 학파는 프로그램을 하나의 수학적 개념 또는 다른 것(제안, 함수 등)의 예로 보지만, 완전히 다른 종류의 접근법이 있는데, 그들은 프로그래밍을 기계와 대화하고 우리가 그것으로부터 원하는 것을 설명하는 방법으로 본다.이러한 관점에서 프로그램은 역동적이고 유기적으로 성장하는 실체이며, 정적인 유형의 프로그램과는 정반대이다.
동적인 언어를 그 방향으로의 스텝이라고 생각하는 것은 당연해 보인다.프로그램의 일관성은 하향식으로 그것을 강요하는 선험적 경계가 없이 밑바닥에서 위로 나타난다.이 패러다임은 개발과 학습을 통해 우리, 인간이 우리가 되는 과정을 모델링하는 단계로 볼 수 있다.
같은 컨버세이션에서 같은 사용자에 의한 후속 투고:
새로운 T는 고장난 프로그램입니다.그것은 "모든 명제는 진실이다"라는 주장과 동형이다.난 이 일에 별로 관심이 없어.
(이것은, 「어떤 상황에서는 「새로운 T」가 좋을 것 같다」라고 하는 다른 유저의 발언에 대한 대응이었습니다.new T()
형식 삭제로 인해 불가능합니다.(이것은 논란의 여지가 있습니다.T
실행 시 사용 가능하거나 추상 클래스 또는 인터페이스일 수 있습니다.Void
또는 no-module 컨스트럭터가 부족하거나 no-module 컨스트럭터가 프라이빗(예를 들어 싱글톤 클래스로 되어 있기 때문에)하거나 no-module 컨스트럭터가 체크된 예외를 지정할 수 있습니다.일반 메서드가 검출하거나 지정하지 않는 경우는, 그것이 전제입니다.어쨌든 지우지 않고 적어도 쓸 수 있는 건 사실이야T.class.newInstance()
(이러한 문제를 해결합니다.
타입이 명제와 동형이라는 이 견해는 사용자가 정식 타입 이론의 배경을 가지고 있음을 시사한다. (S)그는 "동적인 타입"이나 "런타임 타입"을 좋아하지 않을 가능성이 높으며 다운캐스트나 다운캐스트가 없는 자바를 선호할 것이다.instanceof
(스탠다드 ML과 같은 언어를 생각해 보세요.스탠다드 ML은 매우 풍부한 (정적) 타입의 시스템을 갖추고 있어 동적 의미론은 어떤 타입의 정보에도 의존하지 않습니다.)
참고로 사용자가 트롤링을 하고 있다는 것을 유념할 필요가 있습니다.그는 (정적으로) 타이핑된 언어를 진심으로 선호할 가능성이 높지만, 다른 사람에게 진심으로 그 견해를 설득하려고 하지 않습니다.오히려, 원래의 트윗의 주된 목적은 반대하는 사람들을 조롱하는 것이었고, 그 반대자들 중 일부가 끼어든 후, 사용자는 다음과 같은 후속 트윗을 올렸다. "Java가 활자를 지우는 이유는 Java 사용자들과 달리 Wadler 등이 그들이 무엇을 하고 있는지 알기 때문이다."불행하게도, 이것은 그가 실제로 무슨 생각을 하고 있는지 알아내는 것을 어렵게 만든다; 하지만 다행히도, 그것은 그렇게 하는 것이 그다지 중요하지 않다는 것을 의미하기도 한다.자신의 견해에 대해 실제로 깊이 있는 사람들은 일반적으로 이렇게 컨텐츠가 없는 트롤에 의지하지 않는다.
한 가지 장점은 제네릭스가 도입되었을 때 JVM을 변경할 필요가 없었다는 것입니다.Java는 컴파일러 수준에서만 제네릭스를 구현합니다.
활자 지우는 것이 좋은 이유는 불가능하게 만드는 것이 해롭기 때문입니다.런타임에 type 인수를 검사하지 않도록 하면 프로그램에 대한 이해와 추론이 쉬워집니다.
직관에 반하는 견해에 따르면 함수 시그니처가 더 일반적일수록 이해하기 쉬워집니다.이는 가능한 구현 수가 줄어들기 때문입니다.이 시그니처를 가진 방법을 생각해 봅시다.이 방법은 부작용이 없는 것을 알 수 있습니다.
public List<Integer> XXX(final List<Integer> l);
이 기능의 가능한 구현은 무엇입니까?아주 많이요.이 함수의 기능에 대해서는 거의 알 수 없습니다.입력 목록을 뒤집고 있을 수도 있어요ints를 조합하여 합산한 후 절반 크기의 목록을 반환할 수 있습니다.상상할 수 있는 다른 많은 가능성들이 있다.다음 사항을 고려하십시오.
public <T> List<T> XXX(final List<T> l);
이 기능은 몇 가지 구현이 있습니까?구현에서는 요소의 유형을 알 수 없기 때문에 이제 수많은 구현을 제외할 수 있습니다. 요소를 결합하거나 목록에 추가하거나 필터링할 수 없습니다.아이덴티티(목록 변경 없음), 요소 삭제, 목록 반전 등으로 제한됩니다.이 함수는 시그니처만으로 추론하기 쉽습니다.
자바에서는 언제든지 활자 시스템을 속일 수 있습니다.그 일반적인 방법의 실장은 다음과 같은 것을 사용할 수 있기 때문입니다.instanceof
체크 및/또는 임의의 타입에 대한 캐스트, 타입 시그니처에 근거한 우리의 추론은 쉽게 무용지물이 될 수 있습니다.함수는 요소의 유형을 검사하고 결과에 따라 여러 가지 작업을 수행할 수 있습니다.이러한 런타임 해크가 허용되면 매개 변수화된 메서드 시그니처는 훨씬 더 유용하지 않게 됩니다.
자바가 타입 소거가 없는 경우(즉, 타입 인수가 런타임에 재검증된 경우), 이것은 단순히 더 많은 추론을 불러일으키는 이런 종류의 셰니건을 가능하게 할 것이다.위의 예에서 구현은 목록에 적어도1개의 요소가 포함되어 있는 경우에만 타입 시그니처에 의해 설정된 기대를 위반할 수 있습니다.T
was reified, it could do so even if the list were empty. Reified types would just increase the (already very many) possibilities for impeding our understanding of the code.
Type erasure makes the language less "powerful". But some forms of "power" are actually harmful.
This is not a direct answer (OP asked "what are the benefits", I am replying "what are the cons")
Compared to C# type system, Java type erasure is a real pain for two raesons
You can't implement an interface twice
In C# you can implement both IEnumerable<T1>
and IEnumerable<T2>
safely, especially if the two types do not share a common ancestor (i.e. their ancestor is Object
).
Practical example: in Spring Framework, you can't implement ApplicationListener<? extends ApplicationEvent>
multiple times. If you need different behaviours based on T
you need to test instanceof
You can't do new T()
(and you need a reference to Class to do that)
As others commented, doing the equivalent of new T()
can only be done via reflection, only by invoking an instance of Class<T>
, making sure about the parameters required by the constructor. C# allows you to do new T()
only if you constrain T
to parameterless constructor. If T
does not respect that constraint, a compile error is raised.
In Java, you will often be forced to write methods that look like the following
public <T> T create(....params, Class<T> classOfT)
{
... whatever you do
... you will end up
T = classOfT.newInstance();
... or more advanced reflection
Constructor<T> parameterizedConstructorThatYouKnowAbout = classOfT.getConstructor(...,...);
}
The drawbacks in the above code are:
- Class.newInstance only works with a parameterless constructor. If none available,
ReflectiveOperationException
is thrown at runtime - Reflected constructor does not highlight problems at compile time like the above. If you refactor, of you swap arguments, you will know only at runtime
If I was the author of C#, I would have introduced the ability to specify one or more constructor constraints that are easy to verify at compile time (so I can require for example a constructor with string,string
params). But the last one is speculation
An additional point none of the other answers seem to have considered: if you really need generics with run-time typing, you can implement it yourself like this:
public class GenericClass<T>
{
private Class<T> targetClass;
public GenericClass(Class<T> targetClass)
{
this.targetClass = targetClass;
}
This class is then able to do all the things that would be achievable by default if Java did not use erasure: it can allocate new T
s(표준)T
사용할 것으로 예상되는 패턴과 일치하는 컨스트럭터가 있는 경우) 또는 어레이의T
s. 특정 객체가 Run Time에 있는 경우 동적으로 테스트할 수 있습니다.T
거기에 따라 행동을 바꾸는 등.
예를 들어 다음과 같습니다.
public T newT () {
try {
return targetClass.newInstance();
} catch(/* I forget which exceptions can be thrown here */) { ... }
}
private T value;
/** @throws ClassCastException if object is not a T */
public void setValueFromObject (Object object) {
value = targetClass.cast(object);
}
}
대부분의 답변은 실제 기술적인 세부 사항보다 프로그래밍 철학에 더 관심이 있습니다.
이 질문은 5년 이상 지났지만 여전히 의문점이 남아 있습니다.기술적 관점에서 유형 삭제가 바람직한 이유는 무엇입니까?결국 답은 (더 높은 수준에서) 비교적 간단합니다.https://en.wikipedia.org/wiki/Type_erasure
런타임에 C++ 템플릿이 없습니다.컴파일러는 각 호출에 대해 완전히 최적화된 버전을 내보냅니다. 즉, 실행은 유형 정보에 의존하지 않습니다.그러나 JIT는 동일한 기능의 다른 버전을 어떻게 취급합니까?기능만 있는 게 낫지 않을까요?JIT가 모든 다른 버전을 최적화하지 않았으면 합니다.그럼 안전은요?창밖으로 내보내야 할 것 같아요
잠깐만 기다려 주세요.어떻게요?NET은 그것을 합니까?반성!이렇게 하면 하나의 함수를 최적화하고 런타임 유형 정보도 얻을 수 있습니다.그리고 그것이 이유입니다.이전에는 NET 제네릭스가 느리기도 했습니다(비록 많이 좋아졌지만).그게 편리하지 않다고 주장하는 게 아니야!그러나 이것은 비싸고 꼭 필요하지 않을 때는 사용하지 말아야 한다(컴파일러/인터프리터는 반사에 의존하기 때문에 동적 입력 언어에서는 비싸다고 생각되지 않는다).
이 방법으로 유형 삭제를 사용하는 범용 프로그래밍은 오버헤드가 거의 없습니다(일부 런타임 체크/캐스트는 여전히 필요). https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
같은 코드가 여러 유형에 사용되므로 c++와 같은 코드 블러트를 회피합니다.다만, 타입 삭제에는 가상 디스패치가 필요하지만, c++-code-blat 어프로치에서는 non-dispatched generic을 실행할 수 있습니다.
언급URL : https://stackoverflow.com/questions/20918650/what-are-the-benefits-of-javas-types-erasure
'programing' 카테고리의 다른 글
MySQL에서 FULL OUTER JOIN 구문 오류가 보고되는 이유는 무엇입니까? (0) | 2022.11.19 |
---|---|
Java 소스 파일을 생성하는 Java API (0) | 2022.11.19 |
PHP에서 추상 클래스는 무엇입니까? (0) | 2022.11.10 |
Python 3의 sys.maxint란 무엇입니까? (0) | 2022.11.10 |
C에서 *ptr += 1과 *ptr++ 사이의 차이 (0) | 2022.11.10 |