存在的方法...不存在?
代码(编译):
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
。)
Code (which compiles):
for (Method m : ImmutableList.class.getMethods()) {
System.out.println(m);
}
ImmutableList.copyOf(Arrays.asList(new PlayerLevel[0]));
Output (annotated and shortened):
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;
Huh?
(If the logs are not clear enough, I get an error saying that ImmutableList.copyOf(List)
is not a method, but by looping through all the methods I see there is a copyOf(Iterable)
, and List implements Iterable
.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
两种方法在编译时兼容。但运行时是另一个野兽。我假设您的代码针对较旧版本的 Google Collections 进行编译,但针对较新版本运行。
编辑:
详细情况:
给定以下代码行,
编译器开始在
ImmutableList
中查找名为copyOf
的合适方法,并有一个参数兼容静态类型List
。编译器可见的类版本仅提供一个匹配项:请注意,编译器对
tmpArray
的实际类型不感兴趣,仅考虑静态类型(又名“正式类型”)。编译器将所选方法的签名写入类文件中。
在运行时,类加载器/链接器读取类,查找方法的签名
,并对
执行查找(不是搜索!) >ImmutableList
正是给定的签名。 兼容性在这里并不重要,这是编译器的工作。如果您像这样使用反射,您会得到相同的结果:在这两种情况下,Java 只是简单地使用给定类型执行查找。它不会执行类似“可以使用给定类型调用的返回方法”之类的搜索。
在您的情况下,运行时类路径和编译时类是不同的。因此类加载器/链接器无法执行查找。
退一步
这个问题显示了不同级别的兼容性:
您可以使用这些关键字浏览本网站或在 Google 上获取更多信息。 演进的基于 Java 的 API 的三个部分是二进制兼容性的一个很好的参考。
Both methods are compatible at compile time. But runtime is another beast. I assume, that your code compiles against an older version of Google Collections but runs against a newer version.
Edit:
What happens in detail:
Given the lines
the compiler starts to look for a suitable method in
ImmutableList
with the namecopyOf
and one parameter compatible to the static typeList<String>
. The version of the class visible to the compiler offers exactly one match:Please note, that the compiler is not interested in the actual type of
tmpArray
, only the static type (aka. "formal type") is considered.The compiler writes the signature of the selected method into the class file.
At runtime the classloader / linker reads the class, finds the signature of the method
and performs a lookup (not a search!) on
ImmutableList
for exactly the given signature. Compatibility does not matter here, that was the job of the compiler. You get the same results, if you use reflection like this:In both cases Java simply performs a lookup using exactly the given type. It does not perform a search like "return method(s) which can be called with the given type".
In your case the runtime classpath and the compile time class are different. So the classloader / linker fails to perform the lookup.
One step back
This issue shows the different levels of compatibility:
You can use these keywords to look around this site or on Google for more infos. A good reference for binary compatibility are the three parts of Evolving Java-based APIs.