【问题标题】:Do the semantics of a project in bytecode change when changing all of its access modifiers to public?将所有访问修饰符更改为公共时,字节码中项目的语义是否会发生变化?
【发布时间】:2019-06-05 05:45:10
【问题描述】:

假设我有一个可运行的 jar (A.jar),其中包含 .class 文件。我还有另一个可运行的 jar (B.jar),它与 ​​A.jar 相同,但访问修饰符全部更改为 public(对于字段和方法)。是否有可能更改某些语义?它(B.jar)的工作方式是否与前一个(A.jar)完全相同?有什么危害?

编辑示例: A.jar 包含字节码(.class 文件)。我使用 asm 库对其进行解析,并将其所有修饰符更改为 public。生成的 jar 是 B.jar 文件。

【问题讨论】:

  • A.jar 包含字节码(.class 文件)。例如,我使用 asm 库对其进行解析,并将其所有修饰符更改为 public。生成的 jar 是 B.jar 文件。 (它还包含 .class 文件)
  • 嗯,会破坏的一件事是反射代码,它期望 IllegalAccessError 发生,因为它不再被抛出。此外,列出具有某些修饰符的构造的反射代码的结果会发生变化。
  • 你想做什么?
  • 我正在尝试静态内联某些调用站点,并且在不将访问修饰符更改为公共的情况下,某些内联将失败并在运行修改后的 jar 时抛出非法访问

标签: java jvm bytecode semantics access-modifiers


【解决方案1】:

一种可能的行为变化是私有方法不能覆盖超类中的方法。这意味着将子类方法更改为 public 可能会更改在运行时从虚拟调用调用的方法。

来自 JVM Spec v11 5.4.5

一个实例方法 mC 可以覆盖另一个实例方法 mA 当且仅当 以下是正确的:

mC 与 mA 具有相同的名称和描述符。

mC 未标记为 ACC_PRIVATE。

下列情况之一为真:

mA 被标记为 ACC_PUBLIC。

mA 被标记为 ACC_PROTECTED。

mA 既没有标记 ACC_PUBLIC 也没有标记 ACC_PROTECTED 也没有 ACC_PRIVATE,并且 (a) mA 的声明出现在同一个运行时包中 作为 mC 的声明,或 (b) 如果 mA 在 A 类和 mC 中声明 在类 C 中声明,则存在在 a 中声明的方法 mB B 类,使得 C 是 B 的子类,B 是 A 和 mC 的子类 可以覆盖 mB,mB 可以覆盖 mA。

【讨论】:

  • 不是用 InvokeSpecial 调用的私有方法吗?这意味着修改后的 jar 仍将使用 invokeSpecial 调用这些方法 - 接收器的动态类型仍然无关紧要,公共访问器不会产生影响
  • 嗯,B 扩展了 A。A a = new B(); a.foo();如果还有一个 private B::foo 并更改为 public,它将在上面的示例中调用。编辑:这也是无效的,因为 javac 不允许首先定义私有 B::foo (试图分配较弱的访问权限;是公共的)
  • private 方法是通过 invokespecial 调用的,但包私有方法不是。因此,当您在类层次结构中有两个具有相同签名但在不同包中的包私有方法时,它们不会相互覆盖。当您将它们转至public 时,它们会这样做。此外,invokespecial 仅在引用同一类中的方法时按预期方式工作。正如您在评论中所说,当您进行内联时,无论如何这都行不通。
  • 确实,我已经放弃了某些包含invokeSpecial 的内联。现在我需要对访问修饰符做同样的事情。您提供的示例似乎是我需要处理的一种情况。霍尔格总是来救援! :) +1
  • 另外,从 Java 11 开始,私有方法是通过 invokevirtual 调用的。
猜你喜欢
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-15
  • 1970-01-01
  • 2017-11-11
  • 2021-09-23
  • 1970-01-01
相关资源
最近更新 更多