开发者

Class<List> or Class<List<?>> [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance. Closed 10 years ago.

If we have a variable for the class of a generic class, l开发者_运维百科ike List, what type should it be?

List<Class> c1;

or

List<Class<?>> c2;  


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

i.e. List is raw, but List<?> is generic, and you shouldn't mix-and-match between both raws and generics.


Do you want to represent a runtime class, or a type? (The distinction being that List<String> and List<Integer> are different types, but share the same runtime class).

Type: Use something like a type token.

Runtime class: Since

    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;

does not, I'd opt for using the raw type in the type expression. There really isn't any benefit from specifying the type argument to List because the class does not determine it, and using a wildcard type will require weird casting to get it to the proper type, for instance:

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

Edit: Why it doesn't compile

Lifted from the comments:

why doesn't the 2nd code compile? the code makes perfect sense. Is it a design mistake in JDK? or is there valid reason for the choice?

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-hand type of an assignment must be a subtype of the left-hand type. The getClass() case is analogous.

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

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

(source)

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

(source)

We write |T| for the erasure of type T.

(source)

... and why is it defined like that?

Compiler knows the full generic type of e, but why does e.getClass() must return an erased type.

It's hard to give a definite answer to that, since the spec does not expand on the reasons for that definition. However, it might be because the runtime type might not be a subtype of the static type, a pathological situation that can arise by incorrect suppression of unchecked warnings (c.f heap pollution). By specifying that the return type only contains the erasure, the specification ensures that even in the presence of heap pollution, the class object returned by getClass() is an instance of the declared return type of getClass(). It also serves as a reminder that the runtime the programmer is about to access using the reflection API only thinks in terms of erased types.


Class<? extends List<?>>

since List itself is an interface here, this might be a better option.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜