Class <List> or Class <List <? >>

If we have a variable for a general class like List , what type should it be?

 Class<List> c1; //or Class<List<?>> c2; 
-nine
source share
3 answers

The second, because the first uses the raw type instead of generics.

those. List is raw, but List<?> Is generic and you shouldn't mix and compare between raw and generics.

+10
source

Do you want to represent an execution class or type? (The difference is that List<String> and List<Integer> are different types, but have the same execution class).

Type : use something like a type marker .

Runtime Class : s

  List<String> ls = new ArrayList<String>(); Class<? extends List> c1 = ls.getClass(); Class<List> c2 = List.class; 

compiles but

  Class<? extends List<?>> c3 = ls.getClass(); Class<List<?>> c4 = List.class; 

no, I would choose to use the type raw in the type expression. In fact, there is no use in specifying an argument of type List , because the class does not define it, and using a wildcard type will require strange casting to get it in the corresponding type, for example:

  Class<?> rawClass = List.class; // kludge: do not inline this variable, or compilation will fail Class<List<?>> classForBadAPI = (Class<List<?>>) rawClass; 

Change: why it doesn't compile

Raised from the comments:

why doesn't the second code compile? the code makes sense. Is this a design error in the JDK? or is there a good reason to choose?

List.class is of type Class<List> . Since List<?> And List are different types, Class<List<?>> and Class<List> are unrelated types, but the right assignment type must be a subtype of the left type. The case of getClass() similar.

I would not blame the JDK, they only implemented the rules set out in the language specification itself, in particular:

The class literal type is C.Class , where C is the name of the class, interface, or array type, is Class<C> .

( source )

The call type of the e.getClass() method, where the expression e is of static type T , is Class<? extends |T|> Class<? extends |T|> .

( source )

We write |T| for erasing type T

( source )

... and why is it so defined?

The compiler knows the full parent type of e , but why e.getClass() should return the erased type.

It is difficult to give an unambiguous answer to this question, since the specification does not disclose the reasons for this definition. However, this may be due to the fact that the runtime type may not be a subtype of the static type, but a pathological situation that may arise as a result of incorrect suppression of unverified warnings (see heap pollution ). By specifying that the return type contains only deletion, the specification ensures that even if the heap is dirty, the class object returned by getClass() is an instance of the declared return type getClass() . It also serves as a reminder that the runtime that the programmer is about to get with the reflection API only thinks about erasable types.

+9
source
 Class<? extends List<?>> 

since List itself is an interface, this might be the best option.

+5
source

All Articles