Why can't assign I <? extends Type> to <Type>?
Asked Answered
M

2

7

The following statements:

URLClassLoader ucl = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<URLClassLoader> uclc = ucl.getClass();

fail with error:

Type mismatch: cannot convert from Class<capture#2-of ? extends URLClassLoader> to Class<URLClassLoader>

Why do I need a cast, here?

I found several posts explaining why You can't do the reverse (assign T to a ), but that's (kind of) obvious and understood.

NOTE: I am coding this under eclipse Luna, so I don't know if it's a Luna Quirk or if there's something I really dont understand in generics.

Mixedup answered 9/6, 2014 at 8:11 Comment(0)
P
8

Covariance vs contravariance vs invariance

  • Class<? extends URLClassLoader> is invariant.

As a result,

Class<? extends URLClassLoader> is not a subtype of Class<URLClassLoader>


In Java a variable can hold a reference of an instance of same type or subtype.

Hence,

Class<URLClassLoader> uclc = ucl.getClass();

is invalid.

On the other hand,

Class<? extends URLClassLoader> uclc = ucl.getClass();

would be valid.

Pediatrics answered 9/6, 2014 at 8:36 Comment(4)
Can you eloborate why Class<? extends T> (or Class<?>) is not a subtype of Class<T>? I think it is.Kinnon
@swiki: Try to think in terms of collections. Do you think List<? extends Number> should be assignable to List<Integer>? This will lead to type safety problems and isn't allowed. The opposite assignment is allowed though.Skeleton
Read this fantastic explanation: angelikalanger.com/GenericsFAQ/FAQSections/…Pediatrics
@skiwi: types are ranges of values. Generic types are ranges of types. Class<? extends T> is the type that encompasses all the types that extend from TGobbet
C
2

Why can't assign I <? extends Type> to <Type>?

Because actually <? extends Type> is a supertype of <Type>! Let's follow the specification.

4.10.2 Subtyping among Class and Interface Types:

Given a generic type declaration C<F1,...,Fn>, the direct supertypes of the parameterized type C<T1,...,Tn> are all of the following:

  • C<S1,...,Sn>, where Si contains Ti.

4.5.1. Type Arguments of Parameterized Types:

A type argument T1 is said to contain another type argument T2, written T2 <= T1, if the set of types denoted by T2 is provably a subset of the set of types denoted by T1 under the reflexive and transitive closure of the following rules:

  • T <= ? extends T

We therefore know that since ? extends URLClassLoader contains URLClassLoader, Class<? extends URLClassLoader> is a supertype of Class<URLClassLoader>.

Because a narrowing reference conversion is not permitted within an assignment context, a compilation error occurs.

Also note that this means the reverse assignment is permitted:

Class<URLClassLoader> concrete = URLClassLoader.class;
Class<? extends URLClassLoader> wildcard = concrete;
Cotyledon answered 24/1, 2015 at 20:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.