假设我有一个定义以下抽象方法的超类
public abstract <T extends Interface> Class<T> getMainClass();
现在,如果我想在某个子类中重写它
public Class<Implementation> getMainClass(){
return Implementation.class;
}
我收到有关类型安全和未选中转换的警告:
类型安全:类型
SuperFoo >Class<Implementation>
中getMainClass()
的返回类型SubFoo
需要未经检查的转换,以符合类型Class<Interface>
如果Class<Implementation>
,Class<T>
不属于<T extends Interface>
?有没有办法正确摆脱警告?
答案 0 :(得分:12)
重写方法的返回类型必须是重写方法的返回类型的子类型。
Class<Impl>
不是Class<T>
的子类型<T extends Interface>
。 T在这里不得而知。
Class<Impl>
是每个子类型规则Class<? extends Interface>
的子类型。
关于通配符的一些子类型规则:
适用于任何类型X
A<X>
是A<? extends X>
A<X>
是A<? super X>
如果S
是T
A<? extends S>
是A<? extends T>
A<? super T>
是A<? super S>
更简洁,(<:
表示“是”)的子类型
A<S> <: A<? extends S> <: A<? extends T>
A<T> <: A<? super T> <: A<? super S>
答案 1 :(得分:3)
请考虑以下类似于您的方案:
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!
在这种情况下,未经检查的转化警告会警告您出现意外ClassCastException
的可能性。
但是,在您的情况下,当返回类型为Class<...>
时,这不是问题(据我所知),因此您可以合法地禁止警告:
@SuppressWarnings("unchecked")
public Class<Implementation> getMainClass(){ ... }
另一个选择是让SuperFoo
本身通用:
public class SuperFoo<T extends Interface> {
public abstract Class<T> getMainClass();
}
public class SubFoo extends SuperFoo<Implementation> {
public Class<Implementation> getMainClass() { ... }
}
对于另一个(也许是最好的)选项,请参阅Stas Kurilin的回答。
答案 2 :(得分:1)
试试这个
public abstract Class<? extends Interface> getMainClass();
重组示例 通过这样的警告java试图阻止像这样的案件
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
正如@axtavt提到的例子被打破了。我重组了它。
答案 3 :(得分:0)
为什么你想要public abstract Class<? extends Interface> getMainClass();
而不是public abstract Interface getMainClass();
?
我认为您只需返回Interface
的实例,然后,如果调用者想要访问底层运行时类,只需在返回的对象上调用getClass()
即可。
基本上,我认为你可以做到
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());
}
}