自动转型带来的NoSuchMethodError
前言
更新了core
包里的通用方法, 结果本地代码没问题, 线上代码500
, 看了下localhost.log
, 发现报NoSuchMethodError
. 特此记录下。
重现步骤
1 | // Main.java |
编译javac Main.java Utils.java
运行java Main
后输出page:1, pageSize:10
修改Utils
代码, 将int
改为long
, Main
不用改动
1 | // Utils.java |
只编译Utils
, 执行javac Utils.java
然后运行java Main
, 抛出NoSuchMethodError
.
1 | Exception in thread "main" java.lang.NoSuchMethodError: Utils.test(II)V |
重新同时编译两个文件javac Main.java Utils.java
运行java Main
后又成功输出page:1, pageSize:10
分析
先把修改前的class
文件反编译, 得到如下代码
1 | // Main.class |
将Utils
的int
转为long
之后进行反编译得到如下代码
1 | // Main.class |
同时编译Main.java
和Utils.java
之后进行反编译得到如下代码
1 | // Main.class |
对比可以看到, 正常执行的代码, page
参数的类型是对应的, 自动转型其实是在编译的时候对其进行了强制转换.
当我们修改了方法参数类型后, 只编译部署Utils.class
后, Main
就找不到符合test(int, int)
的方法, 因为Utils.class
只有test(long, int)
方法。
而当我们两个类都进行编译时, Main
检测到Utills.class
没有test(int, int)
, 就会自动在调用的方法里加上强制类型转换(long) var1
.
发生的情景
一般发生在增量更新的项目里面, 本地编译了class
文件, 只替换服务器上对应的文件, 如果是全量更新的项目, 则不会出现这个问题。
如何避免
有两种方法
- 全量更新
- 保留旧的代码, 添加
@Deprecated
注解1
2
3
4
5
6
7
8
9
10// Utils.java
public class Utils {
public static void test(int page, int pageSize){
System.out.println("page:"+page+", pageSize:"+pageSize);
}
public static void test(long page, int pageSize){
System.out.println("page:"+page+", pageSize:"+pageSize);
}
}