gpt4 book ai didi

java - 仅更改方法结果和类加载器 NoSuchMethod

转载 作者:行者123 更新时间:2023-11-30 06:49:43 27 4
gpt4 key购买 nike

我们从一个 jar 和一个类开始,使用一种方法,例如:

boolean foo( int bar ) { ... }

但是,此方法的结果是无用的(事实上,始终为真)并且使用此结果的客户端会因错误而失败。为此,方法更改为:

void foo( int bar ) { ... }

并重新编译所有项目。因此,我们可以假设此 jar 的所有用户都调用该方法:

foo(14);

没有人使用表格(如果有人,则超出此问题的范围):

boolean x = foo(14);

假设没有新的或旧的客户端使用 boolean 结果。

问题是,在目标系统中,新的 jar 在没有升级客户端的情况下被加载。未更新的客户端在查找结果为“boolean”的“foo”方法时失败并出现异常“NoSuchMethod”。即:

  • 客户端有一个像“foo(14);”这样的语句不使用方法结果
  • 客户端是使用带有 boolean 方法的 jar 编译的。
  • 客户端和库加载到目标系统
  • 库使用 void 方法更新为新的 jar
  • 客户端因“NoSuchMethod”而崩溃

问题的根源似乎是,Java 和 C/C++ 都不允许两种仅在结果上不同的方法,而只有 Java“名称修改”在类加载器(链接器)的名称中包含结果类型在 C/C++ 中)正在寻找。

问题是:在这种情况下,有可能以任何方式欺骗库 jar 或类加载器以跳过“NoSuchMethod”异常吗?

最佳答案

此行为完全符合预期。这是因为客户端的编译类包含constant pool ,其中包括对方法的符号引用

假设我们有类 FooClass 有两个方法:

public boolean foo1(int bar) {
return true;
}

public void foo2(int bar) {
// ...
}

假设我们有另一个类Main,我们在其中调用了两个方法:

    FooClass fc = new FooClass();
fc.foo1(1);
fc.foo2(1);

如果我们反汇编 Main.class,我们会看到方法引用不仅在名称上不同,而且在返回类型上也不同(注意 (I)Z(I)V:

     7: astore_1
8: aload_1
9: iconst_1
10: invokevirtual #4 // Method q42340444/FooClass.foo1:(I)Z
13: pop
14: aload_1
15: iconst_1
16: invokevirtual #5 // Method q42340444/FooClass.foo2:(I)V

其中常量池包含:

   #4 = Methodref          #2.#25         // q42340444/FooClass.foo1:(I)Z
#5 = Methodref #2.#26 // q42340444/FooClass.foo2:(I)V

换句话说,它保留原始方法的返回类型并在链接库中查找完全相同的方法,这会导致 NoSuchMethod 异常。

更具体地说,已编译的用户类链接到 FooClass.foo:(I)Z 方法,而您的新库不包含具有此类描述的方法,而仅包含 FooClass.foo :(I)V.

结论:如果不保留旧方法签名(可能最好用 @Deprecated 注释注释该方法)或重新编译客户端代码,则无法解决此问题.

关于java - 仅更改方法结果和类加载器 NoSuchMethod,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42340444/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com