Java AbstractMethodError原因案例詳解

背景

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

AbstractMethodError類圖

現在明確瞭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。

到此這篇關於Java AbstractMethodError原因案例詳解的文章就介紹到這瞭,更多相關Java AbstractMethodError內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: