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 u开发者_StackOverflow社区nder 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 ofA<? extends X>
A<X>
is a subtype ofA<? super X>
if S
is subtype of T
A<? extends S>
is a subtype ofA<? extends T>
A<? super T>
is a subtype ofA<? 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.
Why do you want to have something like public abstract Class<? extends Interface> getMainClass();
rather than public abstract Interface getMainClass();
?
I think you can simply return an instance of Interface
, and then, if the caller wants to have access to the underlying runtime class can simply call getClass()
on the returned object.
Essentially, I think you can simply do
public InterfaceImpl implements Interface {
// ...
};
public abstract class A {
public abstract Interface getMainClass();
// ...
}
public class AImpl {
return new InterfaceImpl();
}
public class Main {
public static void main(String[] args) {
AImpl aImpl = new AImpl();
Interface i = aImpl.getMainClass();
System.out.println(i.getClass());
}
}
精彩评论