在项目中偶尔会出现这样的情况,线上的应用报java.lang.NoSuchMethodError异常,然而开发环境却很正常,出错的类没有修改过,然后根据异常提示补上对应的class文件之后又恢复正常,然后过段时间又发生了这样的情况,对此做了研究。
首先分析了下开发环境与线上环境的区别,我打的上线包都是根据自己修改过的java文件路径打成压缩包的格式,而开发环境使用的是eclipse默认的自动编译的模式(即修改过java文件就会编译),再想想之前改动了一个抽象类的返回值(void改成int),出错的类继承了该类,所以在想会不会改动了这个抽象类导致调用该方法的代码的内部发生了变化。于是做了一下实验,首先简单写两个类
父类
public class Father {
public void say() {
System.out.println("Father");
}
}
子类
public class Son extends Father {
public static void main(String[] args) {
new Son().say();
}
}
当然运行结果不是我们关注的内容,我们关注的修改父类的时候改动了哪些代码。
我们可以使用压缩软件(我使用的是2345好压,切换为经典模式)打包的方式来查看修改类会产生哪些新的class文件
例如我将父类Father代码改成如下,由于只是修改输出语句,子类调用无需修改代码
public class Father {
<span style="white-space:pre"> </span>public void say() {
System.out.println("Father change");
}
}
然后记住修改的时间,我修改的时间为22:02。
然后到项目生成class文件的目录进行压缩打包(添加在压缩文件 - >时间->输入修改的时间,如下图)。
建议将秒数写为00,确保时间不会记错。
打完包后之后,进去压缩包后发现,只生成了Father.class
那则可说明父类java文件发生改变的时候只成父类的字节码,子类的字节码没有生成。
我们来将父类改成如下
public class Father {
public String say() {
System.out.println("Father change");
return null;
}
}
由于返回类型void改成String,所以子类调用的代码无需修改。
重复之前的步骤发现,重新生成的class文件如下
由此可得出结论,尽管修改父类方法的返回值,子类调用的java代码无需修改,但是返回的值改变导致父类的class文件变化也促使了子类class文件的重新生成,则说明子类的class文件结构发生变化,然而在项目中我们只关注我们自己修改的代码打成包,有时候会忽略相关子类代码打包,子类没有更新调用不了父类的方法从而报java.lang.NoSuchMethodError,看到这里的小伙伴,还记得之前项目报java.lang.NoSuchMethodError修改过哪些方法么。
注意:
1、该现象只是反映产生java.lang.NoSuchMethodError的其中一种原因,并不能代表全部,该现象也能出现在常量类的修改
2、2345好压会自动生成文件,在检查class文件的时候要点进目录去看看是否存在class文件
看完如果仍有问题,欢迎留言交流。