Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 仅更改方法结果和类装入器NoSuchMethod_Java_Classloader_Name Mangling - Fatal编程技术网

Java 仅更改方法结果和类装入器NoSuchMethod

Java 仅更改方法结果和类装入器NoSuchMethod,java,classloader,name-mangling,Java,Classloader,Name Mangling,我们从一个jar和一个类以及一个方法开始,如下所示: boolean foo( int bar ) { ... } 然而,这个方法的结果是无用的(事实上,总是正确的),并且使用这个结果进行任何操作的客户端都会出现错误。因此,方法更改为: void foo( int bar ) { ... } 以及所有重新编译的项目。因此,我们可以假设此jar的所有用户调用该方法为: foo(14); 没有人使用此表单(如果有人,则超出此问题的范围): 假设没有新的或旧的客户端使用布尔结果。 问题是,在目标

我们从一个jar和一个类以及一个方法开始,如下所示:

boolean foo( int bar ) { ... }
然而,这个方法的结果是无用的(事实上,总是正确的),并且使用这个结果进行任何操作的客户端都会出现错误。因此,方法更改为:

void foo( int bar ) { ... }
以及所有重新编译的项目。因此,我们可以假设此jar的所有用户调用该方法为:

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

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

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

  • 客户机有一个类似“foo(14);”的语句,没有使用方法结果
  • 客户机是使用jar with boolean方法编译的
  • 客户端和库已加载到目标系统中
  • 库更新为使用void方法的新jar
  • 客户端使用“NoSuchMethod”崩溃
问题的根源似乎是,Java和C/C++都不允许只在结果上不同的两种方法,但只有Java“名称混乱”在类装入器(C/C++中的链接器)所寻找的名称中包含结果类型

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

这只是我的想法


您可以尝试在实际编译后使用作为修补程序修改类的字节码。在字节码中,这样的方法可以共存。

完全可以预料到这种行为。这是因为客户机的编译类包含,其中包括对方法的符号引用

假设我们有class
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):

其中常量池包含:

   #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


结论:如果不保留旧方法签名(最好使用
@弃用的
注释注释该方法),或者通过重新编译客户端代码,则无法解决此问题。

是的,正如您所描述的,但你的建议是,如果不保留旧方法签名或重新编译客户端代码,就无法解决当前的实际问题。不幸的是,我不能“保留”旧方法和新方法,因为Java不允许两种只在结果类型上不同的方法。请将其重命名为
foo2(int-bar)
:)没有其他方法了。对于带有@Override“findClass”的自定义类加载器呢?
     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