代码(编译):
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 }}。)
答案 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的三个部分。