2011-05-12 53 views
8

有一個jar在創建時應該使用方法MyClass.doSomething(List)。此方法已更改爲doSomething(Collection)並放入另一個jar(僅限此類)。Java:更一般的方法簽名給我一個NoSuchMethodError

我把我的第2個罐中,我在classpath第一罐前,但是當我的第一個罐子中的代碼調用MyClass.doSomething()用List我仍然獲得了

java.lang.NoSuchMethodError: MyClass.doSomething(Ljava/util/List;)Ljava/util/List;

這怎麼可能?螞蟻已被用來編譯罐子。

+1

MyClass的兩個罐子存在?如果將第二個jar中的類名更改爲MyOtherClass,該怎麼辦?問題是否消失? – 2011-05-12 11:36:52

+0

yes MyClass存在於兩個罐子中。我把它從jar1中,修改它,將它添加到jar2 – Jordan 2011-05-12 12:13:23

回答

4

一般來說,如果得到NoSuchMethodError,這意味着在運行時使用的目標類的版本與編譯調用類的目標類的版本不同。在你的情況下,這不是一個令人驚訝的錯誤;第一個JAR中的字節碼仍然是針對存在一個不存在需要List,的方法編譯的。

這可能歸結爲Ant的漸進式編譯,並沒有注意到依賴類已經改變,或類似的東西。

如果你乾淨地重建整個項目(至少兩個JAR都是你提到的),應該解決這個問題,因爲編譯器會創建字節碼來調用新的doSomething簽名。

11

源代碼兼容性和二進制兼容性之間有一個重要的區別。

  • 如果V1和V2某些類的兩個版本是二進制兼容的,那意味着根據V1編譯的類對V2運行得很好。
  • 如果某些V1和V2類的兩個版本是源代碼兼容的,那意味着一個能夠編譯V1的類將會很好地對V2進行編譯。

源代碼兼容性確實不是自動暗示了二進制兼容性,正如您所經歷的那樣。

編譯源碼時,要調用的特定方法簽名由編譯器決定並存儲在.class文件中(在本例中爲doSomething(List))。

如果更改了類,並且在添加doSomething(Collection)時刪除了方法doSomething(List),則源代碼兼容性被保留(因爲您可以簡單地針對新類編譯相同的代碼),但二進制兼容性會丟失!

Java語言規範有an entire section on binary compatibility。總結:在將方法的參數類型更改爲更一般的類型(通常是)源兼容的情況下,它是而不是二進制兼容的。

如果你想保留的二進制兼容性,那麼改變就必須是這樣的:

public void doSomething(Collection foo) { ... } // original method with changed argument type 

public void doSomething(List foo) { // new binary compatibility method, just delegates to original one 
    doSomething((Collection) foo); 
} 
+0

感謝您的這些解釋。但是我忘了提及它在我身邊,但不在他身上。有沒有辦法讓我成爲可能,而不是他? – Jordan 2011-05-12 12:11:49