1 Star 1 Fork 1

ZeroMorse/no_such_method

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

运行期间抛出NoSuchMethodError

背景

在开发中常遇到抛出NoSuchMethodError的情景,但想不通找不到方法的问题为什么可以通过编译阶段,所以创建了三个工程来模拟出NoSuchMethod的场景进行研究。

模拟NoSuchMethodError

这里简单的复现了NoSuchMethodError出现的场景:outer有1.0和2.0两个不兼容的版本,caller依赖于outer的2.0版本,而main中又显式指出了outer的1.0版本,执行main中的主方法即报错。

下面是main的依赖树:

[INFO] com.example:main:jar:1.0-SNAPSHOT
[INFO] +- com.example:caller:jar:1.0:compile
[INFO] \- com.example:outer:jar:1.0:compile

步骤

1. 生成1.0版本的outer

1.1 创建Painter类,其中包含一个接收String类型的print方法。

package org.example;

public class Painter {

    // 1.0
    public static void print(String name) {
        System.out.println("Hello " + name);
    }
}

1.2 设置pom中的version为1.0

1.3 运行mvn clean install安装到本地仓库

2. 生成2.0版本的outer

2.1 更新Painter类,更新print方法,改为接收一个Integer类型的参数。

package org.example;

public class Painter {

    // 1.0
    //public static void print(String name) {
    //    System.out.println("Hello " + name);
    //}

    // 2.0
    public static void print(Integer i) {
        System.out.println("Hello NO." + i);
    }
}

2.2 设置pom中的version为2.0

2.3 运行mvn clean install安装到本地仓库

3. 创建caller

3.1 caller依赖于2.0版本的outer,pom片段如下

    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>outer</artifactId>
            <version>2.0</version>
        </dependency>
    </dependencies>

3.2 创建Caller类,调用2.0版本outer中的Painter

package com.example;

import org.example.Painter;

public class Caller {
    public static void call() {
        Painter.print(1);
    }
}

3.3 运行mvn clean install安装到本地仓库

4. 创建main

4.1 设置pom依赖如下

    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>caller</artifactId>
            <version>1.0</version>
        </dependency>

        <dependency>
            <groupId>com.example</groupId>
            <artifactId>outer</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

4.2 新建Main类,其中有main方法来调用Caller中的静态方法

package com.example;

public class Main {
    public static void main(String[] args) {
        Caller.call();
    }
}

4.3 编译mvn compile -X,我们可以看到最终使用的outer版本为1.0,并且并没有报错

[DEBUG] com.example:main:jar:1.0-SNAPSHOT
[DEBUG]    com.example:caller:jar:1.0:compile
[DEBUG]    com.example:outer:jar:1.0:compile

[INFO] BUILD SUCCESS

4.4 运行main中的主函数,抛出NoSuchMethodError,命令为mvn exec:java -Dexec.mainClass="com.example.Main" -X,结果如下

java.lang.NoSuchMethodError: org.example.Painter.print(Ljava/lang/Integer;)V
    at com.example.Caller.call (Caller.java:7)
    at com.example.Main.main (Main.java:5)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:282)
    at java.lang.Thread.run (Thread.java:748)

原因分析

为什么编译时不报错,因为依赖的jar已经编译过,无需再编译,所以不报错。或者说,编译过程中只会检查当前java文件的正确性,不会关心依赖的class的正确性。而在运行时则动态加载类,才发现找不到方法,故抛出NoSuchMethodError。

验证

将Main反编译,使用命令javap -c com.example.Main,结果如下

Compiled from "Main.java"
public class com.example.Main {
  public com.example.Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method com/example/Caller.call:()V
       3: return
}

可以看到main的编译过程中并没有涉及到对outer工程中Painter#paint方法的引用,所以不会在编译期间发现这个问题。

而如果使用1.0版本的outer作为caller的依赖,则在编译时就会报异常,编译命令:mvn clean compile,异常片段如下

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project caller: Compilation failure
[ERROR] /no_such_method/caller/src/main/java/com/example/Caller.java:[7,23] 不兼容的类型: int无法转换为java.lang.String

空文件

简介

用于研究项目运行时抛出NoSuchMethodError,类似的还有NoClassDefFoundError等 展开 收起
Java
取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Java
1
https://gitee.com/zero12345/no_such_method.git
git@gitee.com:zero12345/no_such_method.git
zero12345
no_such_method
no_such_method
master

搜索帮助