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

发布于 2024-12-13 20:28:48 字数 934 浏览 2 评论 0原文

代码(编译):

    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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

苍白女子 2024-12-20 20:28:48

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

编辑
详细情况:

给定以下代码行,

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

编译器开始在 ImmutableList 中查找名为 copyOf 的合适方法,并有一个参数兼容静态类型List。编译器可见的类版本仅提供一个匹配项:

ImmutableList.copyOf(Collection<T> arg0);

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

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

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

ImmutableList.copyOf(Collection<T> arg0);

,并对执行查找(不是搜索!) >ImmutableList 正是给定的签名。 兼容性在这里并不重要,这是编译器的工作。如果您像这样使用反射,您会得到相同的结果:

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

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

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

退一步

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

  • 二进制兼容性:放入一个新的 jar 即可。
  • 源代码兼容性:您必须编译源代码,但不必更改它。
  • 行为兼容性语义兼容性:必须更改客户端代码。

您可以使用这些关键字浏览本网站或在 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

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

the compiler starts to look for a suitable method in ImmutableList with the name copyOf and one parameter compatible to the static type List<String>. The version of the class visible to the compiler offers exactly one match:

ImmutableList.copyOf(Collection<T> arg0);

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

ImmutableList.copyOf(Collection<T> arg0);

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:

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

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:

  • Binary compatibility: Throw in a new jar and that's it.
  • Source compatibility: You have to compile your source but you don't have to change it.
  • Behavioural compatibility or Semantic compatibility: The client code must be changed.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文