编程语言
首页 > 编程语言> > java – 存在的方法……不是吗?

java – 存在的方法……不是吗?

作者:互联网

代码(编译):

    for (Method m : ImmutableList.class.getMethods()) {
        System.out.println(m);
    }

    ImmutableList.copyOf(Arrays.asList(new PlayerLevel[0]));

输出(注释和缩写):

public final void com.google.common.collect.ImmutableList.add(int,java.lang.Object)
----> public static com.google.common.collect.ImmutableList com.google.common.collect.ImmutableList.copyOf(java.lang.Iterable)
public static com.google.common.collect.ImmutableList com.google.common.collect.ImmutableList.copyOf(java.util.Iterator)
                 (lots of other methods)

java.lang.NoSuchMethodError: com.google.common.collect.ImmutableList.copyOf(Ljava/util/Collection;)Lcom/google/common/collect/ImmutableList;

咦?

(如果日志不够清楚,我得到一个错误,说ImmutableList.copyOf(List)不是一个方法,但通过循环遍历所有方法,我看到有一个copyOf(Iterable),而List实现了Iterable.)

解决方法:

两种方法在编译时都兼容.但运行时是另一种野兽.我假设您的代码针对较旧版本的Google Collections进行编译,但针对较新版本运行.

编辑:
详细情况:

鉴于线条

List<String tmpArray = Arrays.asList(new PlayerLevel[0]);
ImmutableList.copyOf(tmpArray);

编译器开始在ImmutableList中寻找一个合适的方法,名称为copyOf,一个参数与静态类型List< String>兼容.编译器可见的类的版本只提供一个匹配:

ImmutableList.copyOf(Collection<T> arg0);

请注意,编译器对tmpArray的实际类型不感兴趣,只考虑静态类型(又称“正式类型”).

编译器将所选方法的签名写入类文件.

在运行时,类加载器/链接器读取类,找到方法的签名

ImmutableList.copyOf(Collection<T> arg0);

并在ImmutableList上执行查找(而不是搜索!)以获得确切的给定签名.兼容性在这里无关紧要,这是编译器的工作.如果你使用这样的反射,你会得到相同的结果:

ImmutableList.class.method("copyOf", Collection.class);

在这两种情况下,Java只使用完全给定的类型执行查找.它不执行类似“可以使用给定类型调用的返回方法”的搜索.

在您的情况下,运行时类路径和编译时类是不同的.因此类加载器/链接器无法执行查找.

退一步

此问题显示了不同级别的兼容性:

>二进制兼容性:扔进一个新罐子就是这样.
>源兼容性:您必须编译源代码,但不必更改它.
>行为兼容性或语义兼容性:必须更改客户端代码.

您可以使用这些关键字浏览此网站或Google以获取更多信息.二进制兼容性的一个很好的参考是Evolving Java-based APIs的三个部分.

标签:nosuchmethoderror,java,guava,classpath
来源: https://codeday.me/bug/20190826/1732718.html