2017-02-15 44 views
2

我試圖做這樣的事情:Java的泛型列表<>

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>一個java.util.List動態只有通過具有例如String.classfoo.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; 

..是不是無論是工作!

List<String> list; 

..works,當然。

那麼StringString.class之間有什麼區別?

還是有辦法設置的值,如:

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

「不過,編譯器只是說‘不’。」因爲這不是泛型。它們用於在編譯時強制執行類型安全;如果您直到運行時才知道類型,泛型不能幫助您。 –

+0

我明白了你的觀點。想象一下這個類型在編譯時是衆所周知的:Class cl = String.class;列表列表; 它仍然不會被編譯。 –

+0

從技術上講,這不是一個編譯時常量表達式。但是你不能這樣做:泛型不能基於*變量*,而是變量的*類型*。 –

回答

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泛型只是casts的一個縮寫:編譯器自動爲你插入casts,並檢查這些casts生成的類型是否匹配。


你可以做你在你的例子中描述的,雖然有點,只是沒有使用枚舉。 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對反射攻擊的抵抗等)。但是你有其他有用的東西,所以要權衡你的用例。