假设我有像这样的简单类

public interface Something{
    public void doSomtehing()
}

class A{
    public int getAVal(){
        return 0;
    }
}

class AWithSomething extends A implements Something{
    public void doSomething{
        //in fact do nothing, HAHA
    }
}

abstract class B{
    public abstract <T extends A & Something> T getAWithSomething()
}

class C extends B{

    //allowed??? gives warnig about unchecked conversion
    public A getAWithSomething {
        return new A();
    }
}

class D extends B{

    //same unchecked warning
    public AWithSomething getAWithSomething(){
        return new AWithSomething();
    }
}

C c = new C();
//not implemented but seems valid
c.getAWithSomething().doSomething();

D d = new D();
d.getAWithSomething().doSomething();


所以我的主要问题是:为什么编译器为什么允许类C仅返回A而不检查其是否在编译时实现了接口?

编辑(由于达里扬的评论):
嗯,但我不允许这样声明:

class C extends B{

    //not allowed!
    public Something getAWithSomething {
        return new Something(){
            doSomething(){}
         };
    }
}

最佳答案

JLS将其称为migration compatibility。应该允许库实现者在不破坏客户端(B)的情况下泛化其API(C)。实际上,可以将B替换为List,将getAWithSomething()替换为get(int),并使用自定义C实现(例如apache commons List)替换FixedSizeList

方法签名中的类型变量被擦除为原始类或接口类型。 T中的类型变量B.getAWithSomething()被擦除到其最左侧的A。迁移兼容性基于生成的方法签名A getAWithSomething()。这意味着重写getAWithSomething()的子类必须声明A的返回类型或其子类型。

请注意,您会收到一条警告,提示“小心,您正在将A传递为A&Something,这可能会出错”。它可以:在返回的doSomething()上调用A将抛出一个ClassCastException,因为A无法转换为Something

09-05 16:28