为什么在编译时没有检查多边界泛型

时间:2013-06-17 09:10:20

标签: java generics interface extension-methods

假设我有像这样的简单类

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而不检查它是否在编译时实现接口?

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

class C extends B{

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

1 个答案:

答案 0 :(得分:1)

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

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

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