问题
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<?>>
回答1:
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<?>>
.
回答2:
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:
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!
来源:https://stackoverflow.com/questions/6065998/how-to-declare-class-class-with-valid-generics