我可以在Java中的ArrayList <t>实例上使用类字段吗?</t>

时间:2011-09-22 08:03:36

标签: java generics reflection

我有这个代码,编译:

new TypeToken<ArrayList<ServerTask>>() {}.getType()

然后我尝试了

ArrayList<ServerTask>.class

无法编译。

我是Java编程的新手(来自C#),我认为T.class与C#中的typeof(T)完全相同。显然有一些我不理解的基本内容,所以我的问题是ArrayList<ServerTask>.class出了什么问题,我别无选择,只能使用new TypeToken<ArrayList<ServerTask>>() {}.getType()?是否有更短(更好,更健全)的形式?

感谢。

4 个答案:

答案 0 :(得分:11)

不幸的是(?)Java使用Type Erasure实现了泛型。

这意味着没有构造来获取泛型类型,并且在运行时,您的ArrayList实际上只存储对象。

确切地说,Java中的Generics是一个仅编译时的构造。它们仅在编译时保证类型安全。

编辑: 我刚注意到这段代码 -

new TypeToken<ArrayList<ServerTask>>() {}.getType()

这是类型擦除限制的解决方法。如果扩展具有特定类型的泛型类,则会保留类型信息。例如:

public interface List<T> {
}

public class StringList implements List<String> {
  // The bytecode of this class contains type information.
}

在您的示例中,您可以轻松扩展类TypeToken,从而使编译器生成包含类型信息的匿名内部类TypeToken.getType()的实现将使用反射为您提供此类型信息。

EDIT2:有关更详细的说明,请查看Reflecting Generics

答案 1 :(得分:1)

您的第一个代码示例创建了一个带有具体通用绑定的TypeToken的匿名子类。返回的类型将是Class的实例。但要注意,因为

(new TypeToken<ArrayList<ServerTask>>() {}.getType()).getClass(TypeToken.class)

将返回false!

在您的第二个代码示例中,您尝试执行Java不支持的操作,因为类型擦除实现了泛型。没有代表ArrayList的类,其泛型参数被绑定...从编译器的角度来看,无论泛型类型如何,ArrayList都是ArrayList,因此表达式不会编译。

这两段代码都可能无法正常运行。如果您需要使用通用参数来玩类,您可能需要查看gentyref,我发现这对于简化API非常有帮助,可以询问您尝试获得答案的各种问题到。

答案 2 :(得分:1)

关于“.class”构造,它不是运算符也不是实例成员,它实际上是一种告诉语言“在点之前找到此类名的Class对象”的方法。是一种构建类文字的方法。

如JLE section 15.8.2中所述,如果您尝试将其与参数化类型(以及其他类型)一起使用,编译器将会抱怨。

答案 3 :(得分:0)

Bringer128给出的示例被视为一种称为pseudo-typedef antipattern的反模式。以下是替代方案:

class TokenUtil{
   public static <T> TypeToken<T> newTypeToken(){
   return new TypeToken<T>();
   }
  public static void main(String[] args) {
    TypeToken<ArrayList<ServerTask>> typeTok = TokenUtil.newTypeToken();
    Type type = typeTok.getType();
   }

}