Java中的NoSuchMethodError

2023/05/30

1. 概述

在本教程中,我们将了解java.lang.NoSuchMethodError以及一些处理它的方法。

2. NoSuchMethodError

顾名思义,NoSuchMethodError在未找到特定方法时发生。此方法可以是实例方法或静态方法。

在大多数情况下,我们能够在编译时捕获此错误。因此,这不是一个大问题。但是,有时它可能会在运行时抛出,然后发现它变得有点困难。根据Oracle文档,如果类已被不兼容地更改,则此错误可能会在运行时发生。

因此,在以下情况下我们可能会遇到此错误。首先,如果我们只对代码进行部分重新编译。其次,如果我们的应用程序中的依赖项存在版本不兼容,例如外部jar。

请注意,NoSuchMethodError继承树包括IncompatibleClassChangeErrorLinkageError。这些错误与编译后不兼容的类更改有关。

3. NoSuchMethodError示例

让我们通过一个例子看看这个错误的实际效果。为此,我们将创建两个类。首先是SpecialToday,它将列出餐厅当天的特色菜:

public class SpecialToday {
    private static String desert = "Chocolate Cake";

    public static String getDesert() {
        return desert;
    }
}

第二个类MainMenu调用来自SpecialsToday的方法:

public class MainMenu {
    public static void main(String[] args) {
        System.out.println("Today's Specials: " + getSpecials());
    }

    public static String getSpecials() {
        return SpecialToday.getDesert();
    }
}

这里的输出将是:

Today's Specials: Chocolate Cake

接下来,我们将删除SpecialToday中的方法getDesert()并仅重新编译这个更新后的类。这次当我们运行MainMenu时,我们注意到以下运行时错误:

Exception in thread "main" java.lang.NoSuchMethodError: SpecialToday.getDesert()Ljava/lang/String;

4. 如何处理NoSuchMethodError

现在让我们看看如何处理这个问题。对于上面的代码,让我们做一个完整的清理编译,包括这两个类。我们会注意到在编译时会捕获错误。如果我们使用像Eclipse这样的IDE,它会在我们更新SpecialsToday时更早地被检测到

因此,如果我们的应用程序遇到此错误,作为第一步,我们将进行完全干净的编译。使用Maven,我们将运行mvn clean install命令。

有时问题出在我们应用程序的外部依赖项上。在这种情况下,我们将首先检查类路径加载器拉取的构建路径中jar的顺序。我们将跟踪并更新不一致的jar。

但是,如果我们在运行时仍然遇到这个错误,我们将不得不深入挖掘。我们必须确保编译时和运行时类和jar具有相同的版本。为此,我们可以使用-verbose:class选项运行应用程序来检查加载的类。我们可以按如下方式运行命令:

$ java -verbose:class cn.tuyucheng.taketoday.exceptions.nosuchmethoderror.MainMenu
[0.014s][info][class,load] opened: /usr/lib/jvm/java-11-openjdk-amd64/lib/modules
[0.015s][info][class,load] opened: /usr/share/java/java-atk-wrapper.jar
[0.028s][info][class,load] java.lang.Object source: shared objects file
[0.028s][info][class,load] java.io.Serializable source: shared objects file

使用有关在运行时加载到各个jar中的所有类的信息,我们可以跟踪不兼容的依赖项。

我们还应该确保两个或多个jar中没有重复的类。在大多数情况下,Maven将帮助直接控制冲突的依赖项。此外,我们可以运行mvn dependency:tree命令来获取我们项目的依赖树,如下所示:

$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] -------------< cn.tuyucheng.taketoday.exceptions:nosuchmethoderror >--------------
[INFO] Building nosuchmethoderror 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ nosuchmethoderror ---
[INFO] cn.tuyucheng.taketoday.exceptions:nosuchmethoderror:jar:1.0.0
[INFO] \- org.junit:junit-bom:pom:5.7.0-M1:compile

我们可以在此命令生成的列表中检查库及其版本。此外,我们还可以使用Maven标签管理依赖项。使用<exclusions>标签,我们可以排除有问题的依赖项。使用<optional>标签,我们可以防止不需要的依赖项被捆绑在jar或war中。

5. 总结

在本文中,我们解决了NoSuchMethodError。我们讨论了此错误的原因以及处理它的方法。有关如何正确处理错误的更多详细信息,请参阅我们关于捕获Java错误的文章。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章