8

作成時にメソッドを使用するはずだった jar がありますMyClass.doSomething(List)。このメソッドは変更されdoSomething(Collection)、別の jar に入れられました (このクラスのみ)。

クラスパスの最初の jar の前に 2 番目の jar を配置しましたが、最初の jar 内のコードがMyClass.doSomething()リストで呼び出している場合でも、

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

そんなことがあるものか ?jar のコンパイルには Ant が使用されています。

4

2 に答える 2

12

ソースの互換性とバイナリの互換性には重要な違いがあります。

  • あるクラス V1 と V2 の 2 つのバージョンがバイナリ互換である場合、V1 に対してコンパイルされたクラスは V2 に対して問題なく動作することを意味します。
  • あるクラス V1 と V2 の 2 つのバージョンがソース互換性がある場合、それは、V1 に対してコンパイルできるクラスが V2 に対しても問題なくコンパイルされることを意味します。

あなたが経験したように、ソースの互換性は自動的にバイナリの互換性を意味するわけではありません。

ソースがコンパイルされると、呼び出される特定のメソッド シグネチャがコンパイラによって決定され、.classファイルに格納されます (この場合はdoSomething(List))。

クラスが変更され、メソッドが追加doSomething(List)されている間にメソッドが削除されたdoSomething(Collection)場合、ソースの互換性は保持されます (同じコードを新しいクラスに対して単純にコンパイルできるため) が、バイナリの互換性は失われます!

Java 言語仕様には、バイナリ互換性に関するセクション全体があります。

要約すると、メソッドの引数の型をより一般的な型に変更することは (通常) ソース互換ですが、バイナリ互換ではありません。

バイナリ互換性を維持したい場合は、次のように変更する必要があります。

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);
}
于 2011-05-12T11:38:07.663 に答える
4

一般に、 が表示された場合はNoSuchMethodError、実行時に使用されるターゲット クラスのバージョンが、呼び出し元のクラスがコンパイルされたターゲット クラスのバージョンと異なることを意味します。あなたの場合、それは驚くべきエラーではありません。List最初の JAR のバイトコードは、存在しないを受け取るメソッドの存在に対してコンパイルされます。

これは、Ant のインクリメンタル コンパイルが、依存するクラスが変更されたことに気付かないか、または同様のことが原因である可能性があります。

プロジェクト全体 (少なくとも、言及した両方の JAR) を完全に再構築すると、コンパイラが新しいdoSomething署名を呼び出すバイトコードを作成するため、この問題は解決されるはずです。

于 2011-05-12T11:37:26.927 に答える