how to declare Class.class with valid generics

2019-02-14 16:28发布

Note: purely out of curiosity and not for any actual use case.

I'm wondering if there is a way to declare the Class Class object with valid type parameters:

Class cc1 = Class.class; //raw type
Class<Class> cc2 = Class.class; //now parameter is raw type
Class<Class<?>> cc3 = Class.class; //compile error: inconvertible types

If Class and Class<?> are interchangeable, why are Class<Class> and Class<Class<?>> not?

EDIT: the question can be generalized to an issue of nested raw type parameters. For example:

ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList>(); //same compile error

EDIT2: I should rephrase the question a little: I know that

Class<?> c = Class.class;

is valid but I'm wondering why Class<Class> is not the same as Class<Class<?>>

3条回答
可以哭但决不认输i
2楼-- · 2019-02-14 16:57

The rule here is that the generic type in the left side must match the generic type in the right side.

Class<?> means a class of any type.

Class<?> c = Class.class; 

Works because Class of any type can be Class<Class>.

Class<Class<?>> cc3 = Class.class;

Do not work because Class.class type is Class<Class> which is not of type Class<Class<?>>

ArrayList<ArrayList<Integer>> lst = new ArrayList<ArrayList<Integer>>();
ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList<?>>();

Works because the two expressions match.

ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList>();

Don't match.

查看更多
霸刀☆藐视天下
3楼-- · 2019-02-14 17:01

Generics have some pretty serious limitations. In this case you can't assign a type to the inner type of Class<Class> because you're actually referencing the raw type, not an implementation of the raw type. It will give you a warning, but you have no way to fix that warning.

Class<Class<?>> by itself isn't an inconvertible type, you just can't assign a class directly to it because it doesn't have the type Class<Class<T>>, it has the type Class<T>.

Think of it another way; try List<List<String>>. To create that, you need to create a List that takes a List of Strings. This works because lists can contain lists.

A Class is more like a primitive than a data object, so I don't think it'd be possible to create a Class that is of type Class of something else.

Edit: your extra question about ArrayList<ArrayList<?>> is a more obvious example of the inconvertible type issue you're having with Class<Class<?>>.

查看更多
成全新的幸福
4楼-- · 2019-02-14 17:08

It's kind of difficult to see exactly what you're asking (or what you're trying to do).. but you can parametrize without raw types.

Class<? extends Object> cc4 = Class.class; // no raw types
Class<?> cc5 = Class.class; // also an option

As far as your last example is concerned, it makes no sense because it appears you want to make an array list of array lists that hold ?, but your declaration isn't declaring an array list of array lists that hold ?.

Properly written (but still not proper Java) would be:

ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList<Integer>>(); // Type mismatch

Which is expected. It doesn't work for the same reason something like the following doesn't work:

Object o = new Object();
Integer i = new Integer(3);

o = i;
i.floatValue();
o.floatValue(); // can't access that method, we need to specifically cast it to Integer

Java types aren't proactively inferred (even in an inheritance chain).

If you want to keep the wildcard in there, you're welcome to, though:

ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList<?>>(); // works!
查看更多
登录 后发表回答