Java中的重构方法和二进制兼容性

10

重构方法时,很容易在Java中引入与代码先前版本不兼容的二进制问题。

考虑将一个方法更改为扩展其参数类型到父接口:

 void doSomething(String x);

 // change it to

 void doSomething(CharSequence c);

使用此方法的所有代码将继续编译而无需更改,但需要重新编译(因为旧的二进制文件将因MethodNotFoundError而失败)。

如果将方法提取到父类中,是否需要重新编译?

// before
public class B extends A{
    protected void x(){};
}

// after
public class A {
    public void x(){};
}
public class B extends A{}

该方法已经从B类移动到其父类A中。同时,可见性已从protected更改为public(但这不是一个问题)。

我是否需要在B类中维护一个“二进制兼容性包装器”,或者它会继续工作(自动分派到父类)?

 // do I need this ?
 public class B extends A{
     // binary compatibility wrapper
     public void x(){ super.x(); }
 }
2个回答

14
“扩宽”会影响方法的签名,因此不具备二进制兼容性。将方法移动到超类中不会影响方法签名,因此可以使用。 Eclipse有一份很好的文档描述API和ABI的兼容性:

http://wiki.eclipse.org/Evolving_Java-based_APIs

更明确的规则在第2部分:

http://wiki.eclipse.org/Evolving_Java-based_APIs_2

我认为您对“更改形式参数的类型”(即您所谓的扩宽)或“将API方法移至类型层次结构中更高级别的类”(即您所谓的拉入父类)感兴趣。


-2

它应该继续自动工作,因为Java具有动态链接


我也曾对扩展方法有同样的想法……但这并不起作用,因为参数的类名成为内部方法名称的一部分。我想知道编译器认为声明该方法的类的名称是否也是如此。 - Thilo
1
“Widening” 影响方法的签名,但将方法移动到超类不会产生影响。请在命令行上尝试一下。 - Brett Kail
JLS中有二进制兼容性的细节。 - Tom Hawtin - tackline

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接