Java - 抽象类和子类的二进制兼容性

6
在Java中,我定义了一个抽象类,其中既有具体的方法,也有抽象的方法,并且必须由第三方开发人员独立地进行子类化。只是为了确保:我能否对抽象类进行任何更改,这些更改与其类源代码兼容但不与其二进制代码兼容?换句话说,在他们编译子类之后,我可以更改抽象类吗?除了例如向其中添加抽象方法或删除由子类调用的受保护方法(当然是源代码不兼容的)之外,是否还有其他更改方式可能会强制他们重新编译子类?
3个回答

9
如果你的系统还没有太晚更改,我建议你这样做。通常覆盖并不是定制功能的好方法,因为它非常脆弱。例如,如果您稍后使用了客户已使用的方法名称(他们现在无意中自动覆盖),那么可能会完全破坏类的不变性。通常更好的提供定制方式是给你的客户一个接口,仅限于定制行为,然后你有一个完全具体的类,依赖于此接口的实例,并在需要使用定制行为时适当地委托给接口。这样,你的代码和客户的代码完全分离,它们不会相互干扰。

谢谢您提供备选方案!这也是我正在考虑的 - 我正在权衡它的复杂性成本(维护对实现的引用并委托给它),但由于这种可插拔的架构是一个要求,所以我会这样做。 - thSoft

5
我假设你在技术上使用“二进制不兼容”的意思;例如,类加载器检测到不兼容并拒绝加载类。
如果您添加了一个可见方法并将其声明为final,并且该方法与第三方子类中的某个现有方法的签名冲突,则还可能引入二进制不兼容性。但是,如果该方法是非final的,则现有方法将变成您(新)方法的重写,这可能会导致问题…但不会导致二进制不兼容性。
同样,添加新的可见字段将导致隐藏,可能导致混乱的行为并破坏对象序列化。但这不会导致二进制不兼容性。
总的来说,这表明您需要考虑应用程序语义问题以及简单的二进制兼容性。而Java类型系统无法帮助您解决这些问题。
为了完整起见,您可以在代码中执行其他一些操作,这些操作会破坏第三方类的二进制兼容性:
- 减少抽象类及其方法的可见性, - 更改用作参数结果和异常类型的其他类的签名, - 更改抽象类扩展的超类链,或对这些类进行不兼容的更改,或 - 更改抽象类实现的接口树,或对这些接口进行不兼容的更改。

感谢您提供全面的答案,并考虑到我也想到但没有描述的任何其他破坏实现者代码的方法。 - thSoft
好的回答。二进制和源代码兼容性规则是非常独立的。理解它们各自的含义非常重要。http://motlin.com/2010/binary-and-source-backwards-compatibility/ - Craig P. Motlin

2

好的。

你可能会无意中使用一个已经被使用的方法名,这个方法现在突然被覆盖了,可能会产生截然不同的结果。

你可能会向类中添加字段,从而破坏序列化等功能。


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