简体   繁体   English

我可以使用子接口重新编译公共API并保持二进制兼容性吗?

[英]Can I recompile a public API with a sub-interface and keep binary compatibility?

I have a public API, used several times across several projects: 我有一个公共API,在几个项目中多次使用:

public interface Process<C extends ProcessExecutionContext> {

    Future<?> performAsync(C context);

}

And an abstract class that takes care of implementing the Future mechanism (not shown). 还有一个抽象类,负责实现Future机制(未显示)。 I know that all projects subclass the corresponding abstract class (for which performAsync is final ) and no single class implements the abstract interface without subclassing the abstract implementor. 我知道所有项目都是相应的抽象类的子类(对于这些抽象类,performAsync是最终的 ),并且没有单个类在没有子类化抽象实现者的情况下实现抽象接口。 This is by design and because this "public" API is "public" within our company. 这是设计上的,因为这个“公共”API在我们公司内是“公开的”。

Finding that Future is too limitative compared to Spring's ListenableFuture I decided to extend the interface to 与Spring的ListenableFuture相比,发现Future太有限了我决定将界面扩展到

public interface Process<C extends ProcessExecutionContext> {

    ListenableFuture<?> performAsync(C context);

}

And I already implemented the ListenableFuture in the single abstract superclass not shown in the example. 我已经在示例中未显示的单个抽象超类中实现了ListenableFuture。 No other implementation exists, by design. 根据设计,没有其他实现存在。

Every caller so far uses Future which is a superinterface of ListenableFuture . 到目前为止,每个调用者都使用Future ,它是ListenableFuture的超级ListenableFuture Code compiles well if you use Future<?> future = processReturningListenable.performAsync(context) . 如果使用Future<?> future = processReturningListenable.performAsync(context)代码编译得很好。

Question is: if I deploy an up-to-date JAR of the public API, containing both the interface and the abstract superclass with ListenableFuture implementation to existing environments, without recompiling all the projects , does the performAsync call still work? 问题是:如果我部署的公共API的跟上时代的JAR,包含两种接口,并与抽象超ListenableFuture落实到现有环境, 而无需重新编译所有的项目 ,并在performAsync电话仍然有效?

Ie does Java grant binary compatibility of interfaces when they are replaced with a method that return a subtype of the original type? 即,当接口被返回原始类型的子类型的方法替换时,Java是否授予接口的二进制兼容性?

I am asking this because 1) I find no one available for doing a simple test with an existing JAR file and 2) having to recompile all projects is a red alert. 我问这个是因为1)我发现没有人可以使用现有的JAR文件进行简单测试,2)必须重新编译所有项目是一个红色警报。

I assume what I ask is possible because Java method names are identified by a signature that counts the method name and the input parameters. 我假设我的要求是可能的,因为Java方法名称由一个计算方法名称和输入参数的签名来标识。 Changing the output parameters doesn't change the method's name 更改输出参数不会更改方法的名称

This has been directly addressed in The Java® Language Specification, §13. 这已在Java®语言规范§13中直接解决 Binary Compatibility, §13.4.15. 二进制兼容性,§13.4.15。 Method Result Type : 方法结果类型

Changing the result type of a method, or replacing a result type with void , or replacing void with a result type, has the combined effect of deleting the old method and adding a new method with the new result type or newly void result (see §13.4.12 ). 改变的方法的结果类型,或与替换结果类型void ,或替换void与结果类型,具有删除旧方法和添加新方法与新的结果类型的或新的组合效果void结果(见§ 13.4.12 )。

The referenced §13.4.12 saying: 引用的§13.4.12说:

...

Deleting a method or constructor from a class may break compatibility with any pre-existing binary that referenced this method or constructor; 从类中删除方法或构造函数可能会破坏与引用此方法或构造函数的任何预先存在的二进制文件的兼容性; a NoSuchMethodError may be thrown when such a reference from a pre-existing binary is linked. 当链接来自预先存在的二进制文件的此类引用时,可能会抛出NoSuchMethodError Such an error will occur only if no method with a matching signature and return type is declared in a superclass. 仅当在超类中未声明具有匹配签名和返回类型的方法时,才会发生此类错误。

So the answer is, no, you can't do that without potentially breaking binary compatibility with existing code. 所以答案是,不,如果不打破与现有代码的二进制兼容性,就不能这样做。

Technically, it's simply wrong to assume that methods are identified by name and parameter types only, on the byte code level, they are always identified by name, parameter types and return type. 从技术上讲,假设方法仅通过名称和参数类型来识别是完全错误的,在字节代码级别上,它们总是通过名称,参数类型返回类型来标识。

But note that the cite above states “ Such an error will occur only if no method with a matching signature and return type is declared in a superclass ”. 但请注意,上面的引用声明“ 只有在超类中没有声明具有匹配签名和返回类型的方法时才会发生此类错误 ”。 This guides to a possible work-around: 这指导了可能的解决方法:

interface LegacyProcess<C extends ProcessExecutionContext> {
    Future<?> performAsync(C context);
}
public interface Process<C extends ProcessExecutionContext> extends LegacyProcess<C> {
    @Override ListenableFuture<?> performAsync(C context);
}

Now, Process inherits a matching method from LegacyProcess , a type that doesn't need to be exported, then overrides it with the more specific return type, as you wish. 现在, Process继承了LegacyProcess的匹配方法,这是一种不需要导出的类型,然后根据需要使用更具体的返回类型覆盖它。 This is called “co-variant return type”. 这被称为“共变型返回类型”。 On the byte code level, there will be a “ Future performAsync(…) ” method which delegates to the actual implementation method “ ListenableFuture performAsync(…) ”. 在字节代码级别,将有一个“ Future performAsync(…) ”方法,该方法委托给实际的实现方法“ ListenableFuture performAsync(…) ”。 This automatically generated delegation method is known as bridge method . 这种自动生成的委托方法称为桥接方法

That way, existing compiled client code continues to work, while every recompiled code will start using the new method directly without the bridge method. 这样,现有的编译客户端代码继续工作,而每个重新编译的代码将直接使用新方法而不使用桥接方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将接口变量分配给子接口变量? - How can I assign an interface variable to a sub-interface variable? 如何使ByteBuddy创建的子接口继承类型注释? - How to make ByteBuddy created sub-interface inherit type annotations? 为什么从超级接口转换为子接口有效? - Why does this casting from a super to a sub-interface work? 我可以将返回类型更改为严格子类型并保留二进制兼容性吗? - Can I change a return type to be a strict subtype and retain binary compatibility? 如何在子类中公开受保护的静态字段? - How can I make a protected static field public in sub class? 使用静态方法将类更改为Java中的接口的二进制兼容性 - Binary compatibility of changing a class with static methods to interface in Java 使用公共字段以外的 getter/setter 来实现二进制兼容性? - Using getter/setter other than public field for binary compatibility? 谁来帮帮我。 用API重新编译后我遇到了这个问题 - Someone help me. I got this problem after recompile with API 可以从接口中省略公共摘要会损害字节码兼容性吗? - Can omitting public abstract from interfaces harm bytecode compatibility? Java二进制兼容性问题:sun.font.FontManager类成为接口 - Java binary compatibility issue: sun.font.FontManager class became interface
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM