在克隆中使用协变返回类型真的会破坏兼容性吗?
我最近遇到过为什么Java 5+ API没有利用协变返回类型? 。
我同意这个问题,在Java 5中,JDK开发人员可以使用协变返回类型进行克隆并更改现有类,以便我们可以编写
ArrayList list = new ArrayList(); ArrayList clone = list.clone();
代替
ArrayList clone = (ArrayList)list.clone();
但由于某些原因,没有那样做。
我做了一些实验来改变我的test.ArrayList.clone
返回类型从Object到ArrayList,看看“以前编译的类无法找到具有新返回类型的方法”,但无法重现问题。 在字节码中,对旧test.ArrayList.clone
的调用看起来像
INVOKEVIRTUAL test.ArrayList.clone()Ljava/lang/Object;
也就是说,方法签名包含返回类型,因此在我将其签名更改为test.ArrayList.clone()Ltest.ArrayList
。 所以似乎老类会破坏,但实际上并不是因为test.ArrayList.class中有2个克隆方法
public clone()Ltest.ArrayList; public bridge clone()Ljava/lang/Object;
第二个是桥梁,它只是调用协变版本
... INVOKEVIRTUAL ArrayList.clone()Ltest.ArrayList; ...
所以旧class继续工作没有问题。
任何人都可以解释更改克隆的返回类型如何破坏字节码?
对链接问题的这个答案确实包含了原因:它会破坏覆盖clone
方法并指定Object
作为返回类型的ArrayList
所有子类。