博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
运行期间抛出NoSuchMethodError模拟及原因分析
阅读量:6222 次
发布时间:2019-06-21

本文共 3817 字,大约阅读时间需要 12 分钟。

运行期间抛出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片段如下

com.example
outer
2.0
复制代码

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依赖如下

com.example
caller
1.0
com.example
outer
1.0
复制代码

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."
":()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复制代码

转载于:https://juejin.im/post/5bd9c75bf265da39301bd712

你可能感兴趣的文章
QT对话框中show和exec的区别
查看>>
Android和C#实时视频传输Demo
查看>>
java并发编程学习:如何等待多个线程执行完成后再继续后续处理(synchronized、join、FutureTask、CyclicBarrier)...
查看>>
Mysql Binlog三种格式介绍及分析
查看>>
70、二维码生成+圆形头像
查看>>
Pazera Free Audio Extractor 中文版 - 轻松将视频背景音乐/对话音频提取出来的免费软件...
查看>>
读取spring配置文件的方法(spring读取资源文件)
查看>>
PostConstruct
查看>>
MyEclipse------快速读取特定目录下的文件的内容(字节输入流)
查看>>
Linq查询操作之排序操作
查看>>
Spring 4支持的Java 8新特性一览
查看>>
RHEL6.2下挂载光驱安装软件
查看>>
YYCache 源码分析(二)
查看>>
2016年第9本:系统之美
查看>>
framebuff 显示子系统
查看>>
php手册杂记
查看>>
Yii2 定时任务创建(Console 任务)
查看>>
lombok+slf4j+logback SLF4J和Logback日志框架详解
查看>>
PHP 单例模式继承的实现方式
查看>>
思维杂谈(1)
查看>>