Let's say I have a super-class that defines the following abstract method
public abstract <T extends Interface> Class<T> getMainClass();
Now if I want to override it in some sub-class
public Class<Implementation> getMainClass(){
return Implementation.class;
}
I get a warning about type safety and unchecked conversion:
Type safety: The return type
Class<Implementation>
forgetMainClass()
from the typeSubFoo
needs unchecked conversion to conform toClass<Interface>
from the typeSuperFoo
Doesn't Class<Implementation>
fall under Class<T>
if <T extends Interface>
? Is there any way to properly get rid of the warning?
the overriding method's return type must be a subtype of the overridden method's return type.
Class<Impl>
is not a subtype of Class<T>
where <T extends Interface>
. T is unknown here.
Class<Impl>
is a subtype of Class<? extends Interface>
, per subtyping rules.
some subtyping rules regarding wildcards:
for any type X
A<X>
is a subtype of A<? extends X>
A<X>
is a subtype of A<? super X>
if S
is subtype of T
A<? extends S>
is a subtype of A<? extends T>
A<? super T>
is a subtype of A<? super S>
More concisely, ( <:
means "is a subtype of" )
A<S> <: A<? extends S> <: A<? extends T>
A<T> <: A<? super T> <: A<? super S>
Consider the following scenario similar to yours:
public class SuperFoo {
public abstract <T extends Interface> List<T> getList();
}
public class SubFoo extends SuperFoo {
private List<Implementation> l = new ArrayList<Implementation>();
public List<Implementation> getList() {
return l;
}
public void iterate() {
for (Implementation i: l) ...;
}
}
SubFoo subFoo = new SubFoo();
SuperFoo superFoo = subFoo;
superFoo.getList().add(new AnotherImplementation()); // Valid operation!
subFoo.iterate(); // Unexpected ClassCastException!
In this case unchecked conversion warning warns you about possibility of unexpected ClassCastException
.
However, in your case, when return type is Class<...>
, it's not a problem (as far as I understand), so you can legally suppress a warning:
@SuppressWarnings("unchecked")
public Class<Implementation> getMainClass(){ ... }
Another option is to make SuperFoo
itself generic:
public class SuperFoo<T extends Interface> {
public abstract Class<T> getMainClass();
}
public class SubFoo extends SuperFoo<Implementation> {
public Class<Implementation> getMainClass() { ... }
}
For yet another (and perhaps the best) option see Stas Kurilin's answer.
try this
public abstract Class<? extends Interface> getMainClass();
reorganized example by such warnings java tried prevents cases like this
class OtherImpl implements Interface{
}
A a = new B();//where A - your abstract class and B - implementation
Class<OtherImpl> other = a.<OtherImpl>getMainClass();//some broken think, But _without_ runtime exception
As @axtavt mentioned example was broken. I reorganized it.
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