存在的方法......不是吗?

时间:2011-11-04 15:10:10

标签: java classpath guava nosuchmethoderror

代码(编译):

    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)和{{1 }}。)

1 个答案:

答案 0 :(得分:6)

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

修改: 会发生什么:

给出行

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

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

ImmutableList.copyOf(Collection<T> arg0);

请注意,编译器实际类型的tmpArray感兴趣,只有静态类型(aka “正式类型”被认为是。

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

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

ImmutableList.copyOf(Collection<T> arg0);

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

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

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

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

退一步

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

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

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