Is it possible to use a class field in an ArrayList <T> instance in Java?

I have this code that compiles:

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

Then i tried

 ArrayList<ServerTask>.class 

which does not compile.

I am new to Java programming (came from C #) and I thought that T.class is the exact equivalent of typeof(T) in C #. There seems to be something really basic that I don’t understand, so my question is what is wrong with ArrayList<ServerTask>.class and I have no choice, but use new TypeToken<ArrayList<ServerTask>>() {}.getType() ? Is there a shorter (nicer, healthier) form?

Thanks.

+7
source share
4 answers

Unfortunately (?) Java implements generics using Type Erasure .

This means that there is no construct to get a generic type, and at runtime, your ArrayList actually only stores objects.

To be precise, Generics in Java is just a compilation. They guarantee type safety only at compile time.

EDIT: I just noticed this bit of code -

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

This is a temporary solution for type erasure restrictions. Type information is saved if you extend a general 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 trivially extend the TypeToken class, forcing the compiler to generate an anonymous inner class containing type information. The implementation of TypeToken.getType() will use reflection to provide you with this type of information.

EDIT2: For a more detailed explanation, see Reflection of Generics .

+11
source

The first code example creates an anonymous subclass of TypeToken with specific common bindings. The return type will be an instance of Class . But be careful because

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

will return false!

In your second code example, you are trying to do something that Java does not support, due to the way generic tools are implemented with the erase type. There is no class that represents an ArrayList whose common parameter is connected ... from the compiler point a ArrayList is an ArrayList , regardless of the general type, so the expression does not compile.

It is possible that not a single piece of code will work completely correctly. If you need to play around classes with common parameters, you might want to look into gentyref , which I found very useful in simplifying the API to ask the types of questions you are trying to get answers to.

+1
source

About the ".class" construct, this is not an operator or instance member; in fact, this is a way of telling the language "go and find the class object for this class name before the dot". Is a way to build class literals .

As stated in JLE section 15.8.2 , the compiler will complain if you try to use it with a parameterized type (among other things).

+1
source

The example provided by Bringer128 is considered an anti-pattern called a pseudo-typedef antipattern . Here is an alternative:

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

All Articles