【发布时间】:2011-02-19 17:51:21
【问题描述】:
在 Java 中,我定义了一个包含具体方法和抽象方法的抽象类,并且它必须由第三方开发人员独立地进行子类化。只是为了确定:我可以对抽象类进行任何与它们的类源兼容但不兼容二进制的更改吗?换句话说:在他们编译了他们的子类之后,我可以更改抽象类吗?向其中添加抽象方法或从中删除由子类调用的受保护方法,这当然是源不兼容的 - 以一种可能迫使它们重新编译其子类的方式?
【问题讨论】:
在 Java 中,我定义了一个包含具体方法和抽象方法的抽象类,并且它必须由第三方开发人员独立地进行子类化。只是为了确定:我可以对抽象类进行任何与它们的类源兼容但不兼容二进制的更改吗?换句话说:在他们编译了他们的子类之后,我可以更改抽象类吗?向其中添加抽象方法或从中删除由子类调用的受保护方法,这当然是源不兼容的 - 以一种可能迫使它们重新编译其子类的方式?
【问题讨论】:
当然。
您可能不小心使用了他们曾经使用过的方法名称,现在突然被覆盖,结果可能截然不同。
您可以将字段添加到混淆序列化等的类中。
【讨论】:
如果现在更改您的系统还不算太晚,我建议您这样做。覆盖通常不是自定义功能的好方法,因为它非常脆弱。例如,如果您稍后使用您的客户使用过的方法名称(他们现在无意中自动覆盖),那么覆盖可能会完全破坏您的类的不变量。提供定制的一种通常更好的方法是给你的客户一个仅限于定制行为的接口,然后你有一个完全具体的类,它依赖于这个接口的一个实例,并在需要时适当地委托给接口使用自定义的行为。这样一来,您的代码和客户的代码就完全分离了,不会互相干扰。
【讨论】:
我假设您使用的是技术意义上的“二进制不兼容”;例如类加载器检测到不兼容并拒绝加载类。
如果您添加一个可见方法并将其声明为final,并且该方法与第三方子类中某些现有方法的签名相冲突,也可能会引入二进制不兼容。但是,如果该方法不是最终的,则现有方法将变成您的(新)方法的覆盖,这可能会导致问题......但不会导致二进制不兼容。
同样,添加新的可见字段会导致隐藏,可能会导致令人困惑的行为并会破坏对象序列化。但这不会导致二进制不兼容。
总的来说,这表明您需要考虑应用程序语义问题以及简单的二进制兼容性。 Java 类型系统在这方面帮不了你。
为了完整起见,您可以在代码中执行其他一些操作,这些操作会破坏 3rd 方类的二进制兼容性:
【讨论】: