通用方法的“非法”实现:为什么我没有得到任何编译错误?

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)

如果我尝试与以前相同的“非法”实现,则实际上会收到编译错误。似乎更奇怪了...

Eug*_*ene 2

你甚至可以这样做:

    @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)

并且在实现中您强制类型正确。实际上,第二个例子是直观的——因为它不能编译;这预期的。另一方面,第一个依赖于非泛型方法的某些兼容性规则,该规则允许覆盖相同的擦除。