Aka*_*ami 8 java generics typechecking
我有一个包含带有此签名的方法的接口:
<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);
Run Code Online (Sandbox Code Playgroud)
基本上,MergeProperty是一个不实现的类RestartApplicant,并且RestartApplicant是一个函数接口,其中包含的方法对于理解此问题并不重要。
这里是要抓住的地方。当我创建实现此接口的类时,Java允许我运行以下代码而没有任何编译错误:
public class MyImplementation implements MyInterfacePreviouslyDescribed {
@Override
public List<MergeProperty<MathObject>> loadPropertiesFrom(MathObject p1, MathObject p2) {
return Arrays.asList(
// some random instances of MergeProperty that do not implement RestartApplicant
);
}
}
Run Code Online (Sandbox Code Playgroud)
显然,我不尊重那里的实现限制。鉴于此签名,名单我回用Arrays.asList(...)也不要需要包含实现元素RestartApplicant。记住,MergeProperty不要实现RestartApplicant。因此,这很可能最终会导致某个地方的转换错误。
不过,我仍然收到警告:
Type safety: The return type List<Main.MergeProperty<Main.MathObject>> for
loadPropertiesFrom(Main.MathObject, Main.MathObject) (...) needs unchecked
conversion to conform to List<Main.MergeProperty&Main.RestartApplicant> from the
type Main.Test<Main.MathObject>
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么我只会收到警告?在我看来,我不应该能够编译我的代码。有什么特别的原因吗?
提前致谢。
编辑
在玩完代码后,我发现如果将“泛型声明”移到类级别,则会导致:
Type safety: The return type List<Main.MergeProperty<Main.MathObject>> for
loadPropertiesFrom(Main.MathObject, Main.MathObject) (...) needs unchecked
conversion to conform to List<Main.MergeProperty&Main.RestartApplicant> from the
type Main.Test<Main.MathObject>
Run Code Online (Sandbox Code Playgroud)
而不只是
interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant>
Run Code Online (Sandbox Code Playgroud)
显然
interface MyInterfacePreviouslyDescribed<T>
Run Code Online (Sandbox Code Playgroud)
代替
List<P> loadPropertiesFrom(T p1, T p2);
Run Code Online (Sandbox Code Playgroud)
如果我尝试与以前相同的“非法”实现,则实际上会收到编译错误。似乎更奇怪了...
你甚至可以这样做:
@Override
public List<String> loadPropertiesFrom(MathObject p1, MathObject p2) {
return Arrays.asList(
// some random instances of MergeProperty that do not implement RestartApplicant
);
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下。这是因为重写的方法不是通用的,并且这些方法的擦除将是List。为什么这是允许的?坦白说我不知道,可能与向后兼容性有关。
在你的第二个例子中,看起来确实应该是:
interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant> {
Run Code Online (Sandbox Code Playgroud)
并且在实现中您强制类型正确。实际上,第二个例子是直观的——因为它不能编译;这是预期的。另一方面,第一个依赖于非泛型方法的某些兼容性规则,该规则允许覆盖相同的擦除。