9

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#. 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? Is there a shorter (nicer, saner) form?

Thanks.

4 Answers 4

13

Unfortunately (?) Java implements generics using Type Erasure.

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

To be exact, Generics in Java are a compile-time only construct. 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. The implementation of TypeToken.getType() will use reflection to give you this type information.

EDIT2: For a more detailed explanation, have a look at Reflecting Generics.

Sign up to request clarification or add additional context in comments.

2 Comments

Actually the example you gave above is considered an anit-pattern called pseudo-typedef antipattern.
@Emil Your link talks about how it is an anti-pattern to extend a class to make the generics declaration shorter. I was referring to Reflecting generics which is different in purpose. Thanks for pointing it out though - the StringList shouldn't actually be used!
1

Your first code sample creates an anonymous subclass of TypeToken complete with concrete generic bindings. The type returned will be an instance of Class. But beware, because

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

will return 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. 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.

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.

Comments

1

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". 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).

Comments

0

The example given by Bringer128 is considered an anti-pattern called pseudo-typedef antipattern.Here is the 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();
   }

}

1 Comment

Hi Emil, the example I gave was not a solution, but an explanation of how generic type information is not erased if the child class is non-generic. Please see this link for a library implementation of the TypeToken class that allows you to get type information of generic parameters using this mechanism - I suspect the OP is using this or something similar.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.