2017-05-09 3 views
2

我々は、エラーを見たことがありますJavaバイトコードとそのようなメソッドエラー

java.lang.NoSuchMethodError: com.nhn.user.UserAdmin.addUser(Ljava/lang/String;)V.

これはノーリターン型を持つメソッドaddUserが見つからないと言っています。これは、ライブラリが更新される可能性がありますが、アプリケーションのバイトコードがまだ古いためです。

しかし、Javaオーバーロードを調べると、Javaは戻り値の型の変更だけでオーバーロードをサポートしないことがわかります。

これは正しいので、バイトコードが呼び出されたメソッドの戻り値の型を知らせる理由と、メソッドの戻り値の型でライブラリが更新されたときにエラーが発生するのはなぜですか。

+0

戻り値の型が変更されてもエラーは発生しませんか?ライブラリのメソッドの結果を割り当ててもライブラリが変更され、voidや互換性のないオブジェクトが返される場合はどうなりますか? –

答えて

0

メソッドがインターフェイスで宣言され、オーバーロードされている可能性があります。したがって、実装されたバージョンのメソッドを変更すると、エラーが発生しました。戻り値の型が一致しないが、名前が同じ場合は、エラーが発生します。コンパイラは、メソッドを呼び出すときに使用する戻り値の型を知ることができないため、戻り値の型だけを変更することはできません。

+0

私はエラーの背後にある理由を理解しました。私の質問は、メソッドのオーバーロードができないとき、戻り値の型だけが変更されたとき、JVMがメソッドの戻り値の型を記録したのはなぜですか?メソッドの戻り値の型情報を格納する方法を教えてください。 – Jobs

1

Javaバイトコードは強く型付けされ、検証されます。つまり、呼び出し元のコードは、呼び出されたメソッドが返すコードと互換性がなければなりません。したがって、呼び出し元のメソッド参照に期待される戻り値の型が含まれていなくても、コードには暗黙の前提が含まれていました。結果をlongとすると、Objectまたはvoidではなく、longが返されることが予測されます。

期待される戻り値の型を示すメソッド参照は検証を単純化し、プロセス全体をより効率的にする。実際のリンケージを実行せずに、期待されるメソッドのシグネチャを使用してメソッドのコードの正しさを検証できます。最終的にメソッド呼び出し命令がリンクされている場合、実行可能コードを検証する必要はなく、シグネチャのみが一致しなければなりません。

これは、Javaのソースコードが少なくとも以前のバージョンでは異なる戻り値の型を定義できなくても、そのように設計された理由です。 Java 5以降、ルールはこれ以上厳しくありません。

は、以下のインターフェイスを検討:

interface StringFunction<R> { 
    R apply(String input); 
} 

起因タイプ消去には、それは、バイトコードレベルでの方法Object apply(String input)を有するであろう。

ここで、次の実装クラスを考える:許可され、より具体的な戻り値の型を宣言しているだけでなく、

class Length implements StringFunction<Integer> { 
    public Integer apply(String input) { 
     return input.length(); 
    } 
} 

ジェネリック型システムによると、それは継承として、それは実際には、Java言語でを必要とします抽象メソッドInteger apply(String)からStringFunction<Integer>。バイトコードレベルで

、それは実際の実装方法Integer apply(String)だけでなく、正式にバイトコードレベルでのinterfaceの契約を履行し、実際の実装方法に委譲Object apply(String input)ブリッジメソッドを持つことになります。ジェネリックが有効戻り型の狭小化を可能にするため

、非ジェネリックメソッドのためにそれを否定する理由は存在しなかった、従って、Java(登録商標)は、いわゆる可能共変戻り型同様のJava 5以降:

class Base { 
    Object getValue() { 
     return null; 
    } 
} 
class Sub extends Base { 
    @Override String getValue() { 
     return "now a string"; 
    } 
} 

です。オーバーロードではありませんが、同じパラメータタイプで異なる戻り値の型を持つ複数のメソッドを持つクラスを生成することは可能です。

これらのケースは、別の方法で処理することもできます。共変リターン・タイプと互換性があるように、それらのメソッドがパラメータ・タイプのみで区別され、その戻り値のタイプが同じか、またはより特定である必要があることを定義することによって、メソッド・テーブルの構築時にJVMがすべてのリターン・タイプそのタイプが本当により具体的であるかどうかを検証することができます。それでも、呼び出し元と呼び出し先の間で適切な契約を結ぶためには、戻り値の型をコード化する必要があります。

+0

これは、私が共分散をカバーするあなたの答えの1つを読む2回目です。私はそれらを読んで、私が間違っていたことを意味するものを理解していることを確信していました... – Eugene

+0

@Eugene:私は本当に[この1]が好きです(http://stackoverflow.com/questions/2723397/what-is-pecs-プロデューサー・エクステンション・コンシューマー・スーパー/ 19739576#19739576) – Holger

関連する問題