제네릭 및 유형 삭제


10

Java의 제네릭은 유형 삭제를 사용하여 구현됩니다. JLS 는 그 영감이 이전 버전과의 호환성이라고 말합니다. 반면에 C # 제네릭은 수정 가능한 곳입니다.

이론적으로 Generics를 "삭제"또는 "수정 가능"으로하여 장단점은 무엇입니까?

Java가 누락 되었습니까?

답변:


8

동기 부여 (역 호환성)는 장점이자 단점입니다. 우리 모두가 수정 가능한 유형을 선호하기 때문에 단점이 있지만 지불 가격은 높았습니다. C #에서 디자인 선택을 고려하십시오. 수정 가능한 유형이 있지만 이제 중복 API가 있습니다. 따라서 매개 변수가있는 모든 클래스에 대해 중복 API가있는 Java API를 상상해보십시오. 이제 레거시 클래스에서 새로운 일반 클래스로 수천 줄의 코드를 포팅하는 것을 상상해보십시오. 이제 중복 API를 단점으로 생각하지 않는 사람은 누구입니까? 그러나 그들은 수정 가능한 유형이 있습니다!

따라서 주요 동기는 "혁명이 아니라 진화"였습니다. 논리적으로 모든 결정에는 장단점이 있습니다.

언급 된 다른 단점 외에도 특정 유형이 제거 될 것이라는 것이 확실하지 않기 때문에 컴파일시 유형 삭제가 어려울 수 있다는 사실을 추가 할 수 있으며 이는 매우 이상하고 찾기 어려운 오류로 이어집니다.

브리지 방법 (이진 호환성을 유지하기 위해 구문 적으로 생성 된이 컴파일러 방법) 의 존재는 단점으로 간주 될 수 있습니다. 그리고 이것이 바로 이전 단락에서 언급 한 오류의 원인 중 하나 일 수 있습니다.

일반적인 유형에 대한 여러 클래스가 아니라 단일 클래스가 있다는 이미 명백한 사실에서 큰 단점이 있습니다. 또 다른 예로 Java에서 동일한 일반 클래스를 사용하여 메소드를 오버로드하는 것이 실패하는 것을 고려하십시오.

public void doSomething(List<One>);
public void doSomething(List<Two>);

수정 가능한 유형 (적어도 C #에서는)의 단점으로 볼 수있는 것은 코드 폭발 을 일으킨다는 사실입니다 . 예를 들어 List<int>하나 개의 클래스이며,이 List<double>그것입니다 같은 다른 완전히 다른 List<string>과를 List<MyType>. 따라서 클래스는 런타임에 정의되어야하므로 클래스가 폭발하고 생성되는 동안 귀중한 리소스를 소비합니다.

new T()다른 답변에서 언급 한 Java 로 정의 할 수 없다는 사실에 관해서는 이것이 유형 삭제의 문제 일뿐 만 아니라 고려하는 것도 흥미 롭습니다. 또한 기본 생성자가 있어야하므로 C #에 "새로운 제약 조건"이 필요합니다. ( Alex Buckley 가 Java에서 새로운 T ()를 사용할 수없는 이유를 참조하십시오 .)


3
CLR에서 참조 유형에 대해 모든 코드에 대해 T하나의 Class<T>코드 사본 만 얻습니다 T. 실제로 사용 된 각 값 유형에 대한 추가 사본 T.
AakashM

@AakashM : 맞습니다. 제네릭 당 하나의 Reference Type 클래스가 있지만 각 Value Type은 고유 한 버전을 만듭니다. 이는 유형에 따라 특수한 저장 공간을 제공하기 때문에 모든 참조는 동일한 스토리지를 사용하지만 값 유형은 유형마다 다른 스토리지를 사용합니다.
Guvante

6

유형 삭제의 단점은 런타임에 일반 유형을 알 수 없다는 것입니다. 즉, 리플렉션을 적용 할 수 없으며 런타임에 인스턴스화 할 수 없습니다.

Java에서는 이와 같은 작업을 수행 할 수 없습니다.

public class MyClass<T> {
    private T t;

    //more methods    
    public void myMethod() {
        //more code
        if (someCondition) {
            t = new T();//illegal
        } else {
            T[] array = new T[];//illegal
        }            
    }       
}

이에 대한 해결 방법이 있지만 더 많은 코드가 필요합니다. 앞에서 언급했듯이 장점은 이전 버전과의 호환성입니다.


3

지워진 제네릭의 또 다른 장점은 JVM으로 컴파일되는 다른 언어가 제네릭에 대해 다른 전략을 사용한다는 것입니다 (예 : Scala의 정의 사이트와 Java의 사용 사이트 공분산). 또한 Scala의 고급 제네릭은 .Net의 Reified 형식에서 지원하기가 더 어려웠습니다. 본질적으로 .Net의 Scala는 C #의 호환되지 않는 통합 형식을 무시했기 때문입니다. 우리가 JVM에서 제네릭을 구체화했다면, 아마도 이러한 제네릭 제네릭은 스칼라에 대해 우리가 정말로 좋아하는 기능에 적합하지 않을 것이며, 아마도 차선책에 빠질 것입니다. 올라 비니의 블로그 에서 인용 ,

이 모든 것이 의미하는 바는 정의 된 제네릭을 JVM에 추가하려는 경우 구현시 자체 버전의 제네릭에서 혁신을 수행하려는 모든 정적 언어와 원하는 모든 동적 언어를 모두 포함 할 수 있다는 것을 확신해야합니다. Java 라이브러리와의 좋은 구현 및 훌륭한 인터페이스 기능을 만듭니다. 이러한 기준을 충족하지 않는 통합 제네릭을 추가하면 혁신을 방해하고 JVM을 다국어 VM으로 사용하기가 훨씬 어려워집니다.

개인적으로 TypeTag오버로드 된 메소드와 충돌하기 위해 스칼라에 바인딩 된 컨텍스트를 단점 으로 사용하지 않아도됩니다. 왜냐하면 전역 (전체 프로그램 및 가능한 모든 언어)에서 언어 당 사용 사이트로 통일의 오버 헤드와 비 융통성이 이동하기 때문입니다. 덜 자주 발생하는 문제입니다.



삭제 된 제네릭을 선호하는 또 다른 이유는 Expression Problem에 대한 솔루션을 존중하는 방식으로 종속성을 주입해야하기 때문입니다. 일반 함수에서 특정 유형의 사례를 테스트하거나 팩토리를 하드 코딩하는 경우 확장 성이 잘못되었습니다.
쉘비 무어 III
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.