踩坑了吗,Eric带你避坑。
假设小明遇到下面的问题:
1.java.lang.IncompatibleClassChangeError: Expected static method
2.java.lang.IncompatibleClassChangeError: Expected non-static method
从报错的核心意思看,由于不兼容的Class.
什么情况下会小明遇到上述问题呢?
遇到问题1的场景:
假如小明有DateUtil.java
其中有个strToDate方法。这里我们假设使用Spring注入。
@Service("dateUtil")
public class DateUtil{
public static Date strToDate(String date,String format) throws ParseException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
Date formatDate = simpleDateFormat.parse(date); return formatDate; }
}
然后我们有个调用类TestDate.java
随便写个方法调用DateUtil.strToDate()方法。
@Autowired
@Qualifier("dateUtil")
DateUtil dateUtil;
public class TestDate{
public void formatDate(){
System.out.println(DateUtil.strToDate("2023-06-06","yyyy-MM-dd"));
}
public static void main(String [] args){
TestDate testDate = new TestDate();
testDate.formatDate();
}
}
现在开始编译代码,执行,一切都顺滑有序,没有问题。
突然不知道处于什么原因,小明鬼使神差地将DateUtil.strToDate方法变成了非static方法,即去掉了static关键字。然后编译代码,执行。这也没问题。重点来了,小明的项目是通过class文件部署的。他本次代码改完后,就只将DateUtil部署了上去。然后执行,就出现了异常:
Exception in thread "Thread-1" java.lang.IncompatibleClassChangeError: Expecting static method
此时将TestDate.class文件反编译。看到代码如下
System.out.println(DateUtil.strToDate("2023-06-06","yyyy-MM-dd"));
可以看出调用方法使用了类调用,即应该调用static方法。
遇到问题2的场景:
好下面的问题刚好相反。
小明看到异常提醒,说expect static,所以小明将上述方法改回了static
但此时,刚好小红开发了另一个类TestDate2.java的formatDate()也调用了DateUtil.strDate方法。小红同样也按部就班,编译代码,本地执行,部署,都没问题。
@Autowired
@Qualifier("dateUtil")
DateUtil dateUtil;
public class TestDate2{
public void formatDate(){
System.out.println(dateUtil.strToDate("2023-06-06","yyyy-MM-dd"));
}
public static void main(String [] args){
TestDate testDate = new TestDate();
testDate.formatDate();
}
}
小明这时候也仅仅将DateUtil.java编译后部署了上去。结果:小红的TestDate2的formatDate()抛出异常:
Exception in thread "Thread-1" java.lang.IncompatibleClassChangeError: Expecting non-static method
为什么呢?
可以通过分析小红的TestDate2.calss.
反编译后,小红调用的代码长这个样子:
System.out.println(this.dateUtil.strToDate("2023-06-06","yyyy-MM-dd"));
也就是说,小红的代码,此时是通过对象调用,而不是类调用调用了strToDate方法。
解决方案:
最终,小明,小红商定使用方案1:
1.将DateUtil.strToDate改为static
2.remove掉调用方法里的Spring注入的属性,直接使用类调用,并把所有的编译class重新部署。
方案2:
1.如果使用DateUtil.strToDate为非static方法,要将所有的调用该方法的类都要重新编译部署。
2.使用对象的方式进行调用。
总结:
1.什么情况下会遇到这个问题:编译时,如果被调用方法是static, 调用类的编译结果是类调用即DateUtil.strTodate(..); 反之,如果被调用方法时非static类,调用类编译结果是对象调用,即this.dateUtil.strToDate(..); 如果实际部署的工具类DateUtil和编译时的版本不一致,则会出现本文的问题。
2.统一编译打包的项目一般不会遇到该问题。通过class部署的项目,当如工具类DateUtil修改并编译后,没有将所有调用类重新部署,就会遇到该问题。
本文代码没有通过项目演示,均为作者在页面手敲,如果觉得有不明的或错误之处,还望指正。