2017-02-15 1 views
2

내가 이런 일을하려고 오전 :자바 일반 목록 <>

1. 접근

Type ty = entityType.getEntityClass(); // could be e.g. String.class 
List<ty> list; 

2. 접근

그러나
Class cl = entityType.getEntityClass(); // could be e.g. String.class 
List<cl> list; 

는, 컴파일러는 단순히 말한다 "아니".

일반 유형 <T>을 설정할 수있는 방법이 있습니까? 예를 들어, String.class 또는 foo.getClass()?

...

내가 실제로 유형 EntityTypeEnum 주어진 매개 변수 목록을 초기화 할하려고하거나 Class 속성 값입니다.

public enum EntityTypeEnum { 
    ARTICLE(Article.class), 
    ORDER(OrderHeader.class), 
    CUSTOMER(Customer.class), 
    CUSTOMER_SESSION(CustomerSession.class); 

    private final Class entityClass; 

    private EntityTypeEnum(final Class entityClass) { 
     this.entityClass = entityClass; 
    } 

    public Class getEntityClass() { 
     return entityClass; 
    } 
} 

건설적인 비판을 환영합니다. 감사합니다.

추가 : (앤디의 코멘트의 응답으로)

Class cl = String.class; 
List<cl> list; 

중 하나를 작동하지 ..is!

List<String> list; 

.. 물론.

StringString.class의 차이점은 무엇입니까?

또는 같은 값을 설정하는 방법이있다 : 당신은 자바 제네릭이 할 수있는 어떤 오해하는

public enum EntityTypeEnum { 
    ARTICLE(Article) 
.. 
+4

없이 "그러나, 컴파일러는 단순히 말한다" "." 그것이 제네릭이 원하는 것이 아니기 때문입니다. 컴파일 타임에 유형 안전을 강화하기위한 것입니다. 런타임까지 유형을 모르는 경우 제네릭에서 도움을받을 수 없습니다. –

+0

나는 당신의 요점을 알아 냈습니다. 이 타입이 컴파일 타임에 잘 알려져 있다고 상상해보십시오 : Class cl = String.class; 목록 목록; 여전히 컴파일되지 않습니다. –

+0

기술적으로는 컴파일 타임 상수 표현이 아닙니다. 그러나 당신은 간단히 이것을 할 수 없습니다 : generics는 * variable *에 기반 할 수 없으며, 변수의 * type *에 기반 할 수 있습니다. –

답변

1

제네릭은 컴파일 타임 개념이기 때문에 작동하지 않지만 런타임 개념으로 사용하려고합니다.

차이점은 컴파일 타임 개념에서 컴파일러는 코드에있는 정보를 기반으로 (즉, 실행하거나 평가하지 않고) 유형을 파악할 수 있어야한다는 것입니다.

여기에이 코드는 문법적으로 올바른 것 :

public enum EntityTypeEnum 
{ 
    ARTICLE(String.class), // just using some builtin types to demonstrate 
    ORDER(Integer.class), 
    CUSTOMER(Double.class), 
    CUSTOMER_SESSION(Short.class); 

    private final Class<?> entityClass; 

    private EntityTypeEnum(final Class<?> entityClass) 
    { 
    this.entityClass = entityClass; 
    } 

    public Class<?> getEntityClass() 
    { 
    return this.entityClass; 
    } 
} 

class Test 
{ 
    // here, T is the type parameter which is determined from the class type 
    public <T> List<T> createList(final Class<T> clazz) 
    { 
    return new ArrayList<T>(); 
    } 

    // this is the demo code on how to use it  
    public void foo() 
    { 
    EntityTypeEnum t = EntityTypeEnum.ARTICLE; 
    List<?> list = createList(t.getEntityClass()); 
    } 
} 

문제는이 많은 도움이되지 않는다는 것입니다. 목록은 목록과 거의 같습니다. 컴파일러는 런타임에 따라 다르므로 유형을 특정 포함 된 객체 클래스로 좁힐 수 없습니다. 당신이 당신의 요소에 대한 공통의 슈퍼 클래스가있는 경우

귀하의 경우를 들어

, 당신은 유형 좁힐이 정보를 사용할 수 있습니다 : 당신이 공통의 부모가있는 경우

public enum EntityTypeEnum 
{ 
    ARTICLE(Article.class), 
    ORDER(OrderHeader.class), 
    CUSTOMER(Customer.class), 
    CUSTOMER_SESSION(CustomerSession.class); 

    private final Class<? extends CommonParent> entityClass; 

    private EntityTypeEnum(final Class<? extends CommonParent> entityClass) 
    { 
    this.entityClass = entityClass; 
    } 

    public Class<? extends CommonParent> getEntityClass() 
    { 
    return this.entityClass; 
    } 
} 

class Test 
{ 
    public <T extends CommonParent> List<T> createList(final Class<T> clazz) 
    { 
    return new ArrayList<T>(); 
    } 

    public void foo() 
    { 
    EntityTypeEnum t = EntityTypeEnum.ARTICLE; 
    List<? extends CommonParent> list = createList(t.getEntityClass()); 
    } 
} 

을하지만,의 어떤 이점이 없다 단지 기록을 통해 위의 코드는 :

List<CommonParent> list = new ArrayList<CommonParent>(); 

및 모든 추가 일반적인 물건을 건너 뛰는 ...

4

: 당신은 단지와 함께, 변수의 를 기반으로 뭔가를 할 수 없습니다 변수의 유형.

기본적으로 Java 제네릭은 캐스트의 생략입니다. 컴파일러는 자동으로 캐스트를 삽입하고 해당 캐스트의 결과 유형이 일치하는지 확인합니다.


일종의 열거 형을 사용하지 않고 예제에서 설명하는 것을 수행 할 수 있습니다. Java에서 열거 형의 단점 중 하나는 모든 요소가 동일한 유형이라는 것입니다.

final class EntityTypeEnumIsh { 
    private EntityTypeEnumIsh() {} 

    static final EntityClassSupplier<Article> ARTICLE = 
    new EntityClassSupplier<>(Article.class); 
    static final EntityClassSupplier<OrderHeader> ORDER = 
    new EntityClassSupplier<>(OrderHeader.class); 
    // ... 

    final class EntityClassSupplier<T> { 
    private final Class<T> clazz; 

    EntityClassSupplier(Class<T> clazz) { this.clazz = clazz; } 

    Class<T> getEntityClass() { return clazz; } 
    } 
} 

당신은 지금 당신이 설명하는 등의 방법으로 다음을 사용할 수 있습니다 :

<T> List<T> method(EntityClassSupplier<T> supplier) { 
    return new ArrayList<>(); 
} 

및 호출

대신 실제 열거를 사용하여, 당신은 대략 열거처럼 보이는 뭔가를 사용할 수 있습니다 예 :

List<Article> list = method(EntityTypeEnumIsh.ARTICLE); 

물론 "실제"열거 형의 모든 정교함을 얻을 수는 없습니다 (예 : 직렬화, r 반사 공격에 대한 저항 등). 그러나 당신은 다른 유용한 것을 얻었으므로 유스 케이스를 위해 무게를 달아보십시오.