在克隆中使用协变返回类型真的会破坏兼容性吗?

我最近遇到过为什么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所有子类。