1. 程式人生 > 其它 >Java AbstractMethodError 原因分析

Java AbstractMethodError 原因分析

https://blog.csdn.net/blomule/article/details/43058111

在這個非常依賴第三方庫完成專案或產品的時代,必須要關注好依賴間的版本是否正確。

 

背景

AbstractMethodError異常對於我來說還是比較不常遇見的,最近有幸遇到,並僥倖的解決了,在這裡把此種場景剖析一番,進入正題,下面是AbstractMethodError在Java的異常機制中所處的位置:

 

現在明確了AbstractMethodError所具有的特性:

1.它是Error的子類,Error類及其子類都是被劃分在非檢查異常之列的,就是說這些異常不能在編譯階段被檢查出來,只能在執行時才會觸發。

2.通過API文件裡面的解釋大致得出的結論就是說A依賴於B,但是執行的時候發現類B的定義發生了改變,這個改變是針對編譯的時候發生了改變,也就是說將類A由java檔案編譯成.class檔案的時候用到了類B的class檔案,但是在執行的時候JVM發現真正用到的B的class檔案和編譯的時候用的不是一個了。於是這個異常就被拋了出來。

至此,AbstractMethodError發生的底層原因也瞭解的差不多了,再往深層的話就是java的編譯機制,以及java程式碼的執行檢查這些更靠近虛擬機器的東東,那些我也沒什麼研究,暫且不表。

底層原因瞭解了,我們繼續談下平常遇到的更直觀的場景:

ClassA ->AbstractClassB ClassA 依賴於AbstractClassB,通常A是我們自己開發的類,而B則是引用的第三方jar包裡面的抽象類。我們的專案中又存在AbstractClassB的多個實現版本,比如:1.0,1.2,2.0等版本,通常主版本號發生了改變的話,一般都是不相容的。

類A

class A {
B dependency = new BImpl();

public void testMethod(){
dependency.changedMethodInDifVersion(arg1, arg2);
}
}
1.0版本的AbstractClassB:

abstract class B {
// v1.0
public abstract void changedMethodInDifVersion(int arg1);
}

class BImpl extends B{
public void changedMethodInDifVersion(int arg1){
System.out.prinln("我是AbstractClassB 的 1.0 版本實現,Class A編譯的時候我沒參與,但是Class A執行的時候我卻參與了。");
}
}
2.0版本的AbstractClassB:

abstract class B {
//v2.0
public abstract void changedMethodInDifVersion(int arg1, String arg2);
}

class BImpl extends B{
public void changedMethodInDifVersion(int arg1, String arg2){
System.out.prinln("我是AbstractClassB 的 2.0 版本實現,編譯的時候是我參與了編譯");
}
}

如果在編譯的時候使用的2.0版本中的BImpl和2.0版本的AbstractClassB,然而執行的時候使用的又是1.0版本的BImpl,那麼就會丟擲AbstractMethodError,這個異常丟擲以後會把執行時真正找到的那個方法簽名給打印出來的,異常資訊會入下:

Exception in Thread XXXXX java.lang.AbstractMehodError package.Class.執行時實際找到的方法

這個時候在你的classpath中尋找這個類,剔除掉不需要的版本就可以了。

如果在編譯的時候使用的2.0版本中的BImpl和2.0版本的AbstractClassB,然而執行的時候使用的又是1.0版本的BImpl 和 1.0版本的AbstractClassB,就會報NoSuchMethodError。
————————————————
版權宣告:本文為CSDN博主「liunim90」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/blomule/article/details/43058111