2017-02-15 80 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对反射攻击的抵抗等)。但是你有其他有用的东西,所以要权衡你的用例。