简体   繁体   English

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

[英]Can I use the class field on an ArrayList<T> instance in Java?

I have this code, which compiles: 我有这个代码,编译:

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

Then I have tried 然后我试过了

ArrayList<ServerTask>.class

which does not compile. 哪个不编译。

I am new to Java programming (came from C#) and I have thought that T.class is an exact equivalent of typeof(T) in C#. 我是Java编程新手(来自C#),我认为T.class与C#中的typeof(T)完全相同。 Apparently there is something really basic that I do not understand, so my question is what is wrong with ArrayList<ServerTask>.class and do I have no choice, but use new TypeToken<ArrayList<ServerTask>>() {}.getType() instead? 显然有一些我不理解的基本内容,所以我的问题是ArrayList<ServerTask>.class有什么问题,我别无选择,但使用new TypeToken<ArrayList<ServerTask>>() {}.getType()而不是? Is there a shorter (nicer, saner) form? 是否有更短(更好,更健全)的形式?

Thanks. 谢谢。

Unfortunately (?) Java implements generics using Type Erasure . 不幸的是(?)Java使用Type Erasure实现泛型。

This means that there is no construct to get the generic type, and at runtime your ArrayList actually only stores Objects. 这意味着没有构造来获取泛型类型,并且在运行时,您的ArrayList实际上只存储对象。

To be exact, Generics in Java are a compile-time only construct. 确切地说,Java中的泛型是仅编译时的构造。 They guarantee type-safety at compile time only. 它们仅在编译时保证类型安全。

EDIT: I just noticed this bit of code - 编辑:我刚刚注意到这段代码 -

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

This is a workaround for the limitations of type erasure. 这是类型擦除限制的解决方法。 Type information is preserved if you extend a generic class with a specific type. 如果扩展具有特定类型的泛型类,则会保留类型信息。 For example: 例如:

public interface List<T> {
}

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

In your example, you are trivially extending the class TypeToken , causing the compiler to generate an anonymous inner class that contains the type information. 在您的示例中,您通常会扩展类TypeToken ,从而导致编译器生成包含类型信息的匿名内部类 The implementation of TypeToken.getType() will use reflection to give you this type information. TypeToken.getType()的实现将使用反射来为您提供此类型信息。

EDIT2: For a more detailed explanation, have a look at Reflecting Generics . 编辑2:有关更详细的解释,请查看Reflecting Generics

Your first code sample creates an anonymous subclass of TypeToken complete with concrete generic bindings. 您的第一个代码示例创建了一个带有具体通用绑定的TypeToken的匿名子类。 The type returned will be an instance of Class . 返回的类型将是Class的实例。 But beware, because 但要注意,因为

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

will return false! 将返回false!

In your second code sample, you're trying to do something that Java doesn't support because of how generics are implemented with type erasure. 在您的第二个代码示例中,您尝试执行Java不支持的操作,因为类型擦除实现了泛型。 There is no class that represents an ArrayList whose generic parameter is bound...from the compiler's point of view an ArrayList is an ArrayList regardless of the generic type, so the expression doesn't compile. 没有类表示其通用参数绑定的ArrayList ...从编译器的角度来看,无论泛型类型如何, ArrayList都是ArrayList ,因此表达式无法编译。

It's possible that neither piece of code is going to work out quite right. 这两段代码都不可能完全正确。 If you need to be playing around classes with generic parameters, you may want to look into gentyref , which I've found to be very helpful in simplifying the API to ask the kinds of questions you're trying to get answers to. 如果您需要使用通用参数来玩类,您可能需要查看gentyref ,我发现它非常有助于简化API以询问您尝试获得答案的各种问题。

About the ".class" construct, it is not an operator nor an instance member, it is actually a way to tell the language "go and find the Class object for this class name before the dot". 关于“.class”构造,它不是运算符也不是实例成员,它实际上是一种告诉语言“在点之前找到此类名的Class对象”的方法。 Is a way of constructing class literals . 是一种构建类文字的方法

As specified in the JLE, section 15.8.2 , the compiler will complain if you try to use it with a parameterized type (among others). 正如JLE 第15.8.2节中所规定的,如果您尝试将其与参数化类型(以及其他类型)一起使用,编译器将会抱怨。

The example given by Bringer128 is considered an anti-pattern called pseudo-typedef antipattern .Here is the alternative: Bringer128给出的例子被认为是一种称为伪类型反模式的反模式。这是另一种选择:

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();
   }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM