The problem is in a generic restriction:
public List<Class<? extends Annotation>> getAnnotations() {
return new ArrayList<>(Arrays.asList(Override.class));
}
Real return type is ArrayList<Class<Override>>
Method expects List<Class<? extends Annotation>>
Class<Override>
is a subtype of Class<? extends Annotation>
Class<? extends Annotation> c = Override.class;
//allowed
ArrayList
is a subtype of a List
, if types of the elements match:List<? extends Number> l = new ArrayList<Integer>();
// allowed
However, this is not allowed:
List<Class<? extends Annotation>> l = Arrays.asList(Override.class);
List<Class<? extends Annotation>> l = new ArrayList<>(Arrays.asList(Override.class));
Is it even possible or Class
wildcards are broken?
I would assume that this is because of the jdk 1.7 type inference nature.
As you may already know, the Arrays.asList(T ... elems)
method is generic, but we seldom explicitly specify the type-parameter which we'd like the method to work with and thus we rely on the type inference feature of the compiler.
So, when the compiler sees an Arrays.asList(Override.class)
statement it will infer that the type-parameter for the method should be replaced with Class<Override>
, i.e. we'd have a version of the method in this form:
public List<Class<Override>> asList(Class<Override> ... elems)
However, if you explicitly set the type parameter for the method to
List<Class<? extends Annotation>> l =
Arrays.<Class<? extends Annotation>>asList(Override.class);
then the compiler will actually know what the type-parameter has to be replaced with and then the version of the .asList()
method would be:
public List<? extends Annotation> asList(Class<? extends Annotation> ... elems)
Now this will compile fine, since Class<? extends Annotation>
is compatible to Class<Override>
. In Java8, the type inference feature is improved even more, so that you don't have to explicitly set the type-parameter for the .asList()
method.
However, the more interesting question goes to
Why
List<Class<Override>>
is not compatible withList<Class<? extends Annotation>>
?
The java.lang.Class
is a final
one, which would help answering the following two questions, the combination of which will answer the above question. :)
So,
List<Class<Override>>
mean?List<Class<Override>>
means that we can add only instances of Class<Override>
and nothing else to the list. Which is great, knowing that we can't even add Class<Override>
sub-classes, since the Class
type is final
.
List<Class<? extends Annotation>>
mean?This type of List
represents a whole family of lists of classes, all of which are subclasses of the Annotation
type, which means that we can successfully add any annotation type (for example, SuppressWarnings.class
, Override.class
, Documented.class
, etc.) to the list.
Lets assume that the following example was actually correct:
List<Class<Override>> overrides = Arrays.asList(Override.class);
List<Class<? extends Annotation>> annotations = new ArrayList<>();
annotations = overrides;
annotations.add(SuppressWarnings.class); //HUGE PROBLEM
annotations.add(Documented.class); //ANOTHER HUGE PROBLEM
The two huge problems come from the fact that we're trying to add some non-Override
instances to the overrides
, which is very wrong.
We have smart enough compiler that can actually detect such possible problems and throwing a compile-time error is the way to prevent us from doing this.
More info:
List<Dog>
a subclass of List<Animal>
?If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With