LinkageError是一個比較棘手的異常,準確的說它是一個Error而不是Exception。java api對它沒有直接的解釋,而是介紹了它的子類:
Subclasses of LinkageError indicate that a class has some dependency on another class; however, the latter class has incompatibly changed after the compilation of the former class.
似乎是說不相容性,既編譯時間,A類用到B類,且這時候A和B是相容的,但是到運行時,A類得到的B(既某個類載入器載入的B類)卻不是A在編譯的時候那個與之相容的B,這個說起來比較複雜,其實就是個二進位相容性問題,和很多程式不能在98上跑是一個道理,程式就是A,而98就是B。事實上,真正出現二進位相容性問題的時候,確實是報NoSuchMethodError或者NoSuchFieldError或者NoClassDefFoundError。Java api對NoSuchMethodError的解釋(其他的解釋幾乎相同):
Thrown if an application tries to call a specified method of a class (either static or instance), and that class no longer has a definition of that method.
Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed. 關鍵詞是“
incompatibly changed ”。 事實證明,當傳統意義上的二進位不相容性(既上面舉的98的例子,或者說incompatibly changed)問題發生的時候,java會報NoSuchMethodError,NoSuchFieldError或者NoClassDefFoundError,這三個類都是LinkageError的子類,所以,就好像java api對LinkageError中的解釋一樣“Subclasses of LinkageError indicate that……”這個解釋並沒有說LinkageError本身應該是在什麼情況下被拋出。倒不是java api顧左右而言他,而是拋出LinkageError的情況實在是很難敘述,《深入java虛擬機器》第二版用近乎一章(比較大的一章,和其它章相比)來解釋這個問題。歸根結底,原因是ClassLoader沒有完全按照設計的那樣設定:
任何一個ClassLoader的執行個體都應該設定一個恰當的ClassLoader執行個體為父類載入器,並且在真正defineClass前,都應該先將這個任務委託給其父類載入器。何為恰當的ClassLoader執行個體?一般來說,就應該是 this.getClass().getClassLoader()(也就是ClassName.class.getClassLoader(),這兩個值是同一個值)的傳回值),或者是一個設計者認為合理的值。
這個值應該保證“相同全限定名的類(可以認為是同一個類,僅僅是可以)不會出現在同一個類的代碼中。”舉例來說,在一個類的一段代碼中(可以是一個方法,或者是一個static塊),如果有classLoaderA載入的 test.Test類,也有classLoaderB載入的test.Test,那麼,把前者的引用指向後者的執行個體的時候,就會報LinkageError。