I get the following compilation message:
[javac] ... error: incompatible types
[javac] exceptionClassHolder = new Holder<>( (new Exception())
Holder<? extends Class<? extends Exception>> exceptionClassHolder;
exceptionClassHolder = new Holder<>( (new Exception()).getClass() );
The reason is that
Exception.class
but an Exception object, java thinks ? extends Exception
is required.getClass()
, again ? extends Class
needed, though Class is final. Certainly one day this will be simplified.
Unfortunately, the existing answers don't explain what's going on here. First, the solution is to simply specify the type argument to Holder
:
Holder<Class<? extends Exception>> exceptionClassHolder;
exceptionClassHolder =
new Holder<Class<? extends Exception>>(new Exception().getClass());
The reason your version didn't work is because new Exception().getClass()
returns a Class<? extends Exception>
, where ?
is a wildcard capture (referred to in the compiler error message as CAP#1
). Since you use the "diamond operator" with new Holder<>
, the compiler infers Class<CAP#1 extends Exception>
for T
and so Holder<Class<CAP#1 extends Exception>>
is the type of the created object.
However, this doesn't match your declared type of Holder<Class<? extends Exception>>
. It uses a nested wildcard, which doesn't capture: while CAP#1 extends Exception
is some specific type extending Exception
, the nested ? extends Exception
represents literally any type extending Exception
.
And while Class<CAP#1 extends Exception>
is a subtype of Class<? extends Exception>
, Holder<Class<CAP#1 extends Exception>>
is not a subtype of Holder<Class<? extends Exception>>
because generics aren't covariant, so the assignment fails.
By manually specifying Class<? extends Exception>
for T
, you help the compiler avoid this "trap".
See my similar answers on these posts: