Jor*_*dan 8 java signature nosuchmethoderror
有一个罐子,当它被创建时应该使用一种方法MyClass.doSomething(List).此方法已更改为doSomething(Collection)并放入另一个jar(仅限此类).
我把第二个jar放在classpath的第一个jar前面,但是当我的第一个jar中的代码MyClass.doSomething()用List 调用时,我仍然得到一个
java.lang.NoSuchMethodError: MyClass.doSomething(Ljava/util/List;)Ljava/util/List;
怎么可能?Ant已被用于编译jar.
Joa*_*uer 11
源兼容性和二进制兼容性之间存在重要差异.
正如您所经历的那样,源兼容性并不会自动暗示二进制兼容性.
编译源代码时,要调用的特定方法签名由编译器决定并存储在.class文件中(在本例中为doSomething(List)).
如果更改了类并且在添加时doSomething(List)删除了该方法doSomething(Collection),则会保留源兼容性(因为您可以简单地针对新类编译相同的代码),但二进制兼容性会丢失!
Java语言规范有关于二进制兼容性的整个部分.
总结一下:虽然将方法的参数类型更改为更通用的类型(通常)源兼容,但它不是二进制兼容的.
如果要保留二进制兼容性,则更改必须如下所示:
public void doSomething(Collection foo) { ... } // original method with changed argument type
public void doSomething(List foo) { // new binary compatibility method, just delegates to original one
doSomething((Collection) foo);
}
Run Code Online (Sandbox Code Playgroud)
一般来说,如果得到NoSuchMethodError,则意味着运行时使用的目标类的版本与编译调用类所针对的目标类的版本不同。就您而言,这并不是一个令人惊讶的错误;第一个 JAR 中的字节码仍然是针对采用 a 的方法的存在进行编译的List,而该方法并不存在。
这可能是由于 Ant 的增量编译没有注意到依赖类已更改,或类似的原因。
如果您对整个项目(嗯,至少是您提到的两个 JAR)进行了彻底的重建,那么这个问题应该得到解决,因为编译器会创建调用新doSomething签名的字节码。