【问题标题】:Java: Is method name/signature resolution done statically (compile-time)?Java:方法名称/签名解析是否静态完成(编译时)?
【发布时间】:2012-02-10 06:56:02
【问题描述】:

我今天遇到了一个有趣的问题,我认为这在 Java 中是不可能的。我针对 jgroups 的 2.6 版编译了我的 java 代码,但在运行时使用了 2.12 版(tomcat Web 应用程序部署)。我收到以下错误

org.jgroups.Message.<init>(Lorg/jgroups/Address;Lorg/jgroups/Address;Ljava/io/Serializable;)

假设从那时起 API 会发生变化,我想将我的代码移植到 jgroups-2.12,但令我惊讶的是,代码在 jgroups-2.12 中编译得很好,并且当我更换了新的 jar 时(没有改变一行我的代码,只是针对 jgroups-2.12 而不是 jgroups-2.6 进行编译),它工作得非常好。

后来才知道2.6中的构造函数Message(Address, Address, Serializable)在2.12中改成了Message(Address, Address, Object)。这意味着在运行时,JVM 试图找到完全相同的方法,但没有成功。

这是否意味着 Java 编译器在编译时会嵌入准确的方法名称和准确的参数,而具有更广泛参数的方法将不起作用?

【问题讨论】:

    标签: java compiler-construction compilation


    【解决方案1】:

    是的,完全正确 - 确切的签名是在编译时绑定的,这就是字节码中包含的内容。

    事实上,这甚至包括返回类型,它不包含在签名中,用于重载等目的。

    从根本上说,如果您更改现有公共 API 成员的任何内容,这将是一个重大更改。您可以避免一些仅语言的更改,例如将String[] 参数更改为String... 参数,或引入泛型(在某些 情况下,如果擦除与以前的代码兼容),但仅此而已。

    Chapter 13 的 Java 语言规范完全是关于二进制兼容性的——阅读它以获取更多信息。但特别是来自section 13.4.14

    更改方法或构造函数的形式参数的名称不会影响预先存在的二进制文件。将方法的名称、形式参数的类型更改为方法或构造函数,或在方法或构造函数声明中添加或删除参数会创建具有新签名的方法或构造函数,并具有以下组合效果删除带有旧签名的方法或构造函数,并添加带有新签名的方法或构造函数(参见 §13.4.12)。

    【讨论】:

    • 如果您添加的泛型与旧代码的绑定不同,即使添加泛型也会使事情变得混乱。这就是泛型具有有点模糊的&lt;T extends SomeClass &amp; SomeInterface&gt; 选项的原因——因此您可以“手动”指定泛型的擦除,从而指定字节码兼容性。
    • @yshavit:是的,你必须小心 - 将编辑以使其更清晰。
    【解决方案2】:

    这是否意味着 Java 编译器在编译时会嵌入准确的方法名称和准确的参数,而具有更广泛参数的方法将不起作用?

    没错。您还可以从收到的错误消息中看到这一点:

    org.jgroups.Message.<init>(Lorg/jgroups/Address;Lorg/jgroups/Address;Ljava/io/Serializable;)
    

    此处包含完整的签名,运行时会寻找完美匹配。

    还有其他几种情况,更改 API 会破坏 Java 中的二进制兼容性,但不会破坏源代码兼容性,例如,当您将原始类型更改为其装箱变体时,反之亦然。正如 Jon 所指出的,只有泛型的更改(但不是所有更改)和使用 VarArgs 语法不会影响运行时方法解析,因为两者都只是编译器功能,不会影响字节码。

    这也意味着当你在一个新的库版本中引入一个方法的重载时,这个重载只会被新版本编译的调用者使用。旧的二进制文件仍然会调用旧的方法,即使它们的参数类型更适合新的重载。

    因此,对于库设计者来说,有时建议不要更改现有方法的签名,而只添加新的重载(并让旧方法转发给新方法,这样调用哪个方法并不重要)。当然,缺点是所有这些重载都掩盖了真正的 API,并且使理解 API 变得更加困难。

    【讨论】:

      【解决方案3】:

      Java 编译器必须在编译后的文件中放入准确的方法名称和准确的参数,以便稍后确定要加载哪个类以及调用哪个方法。否则无法精确调用请求的方法。

      【讨论】:

        猜你喜欢
        • 2023-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多