呼び出されるメソッドのオーバーロード解決


8

私が持っていると仮定しましょうComponentBaseの子で、クラス、ObjectContextDecoratorおよびの孫をObjectContext

public class ComponentBase extends ObjectContextDecorator {
}

public class ObjectContextDecorator extends ObjectContext {

    public void set(String objectTypePath, String characteristicName, Object value) {
        //...
    }
}

public class ObjectContext {
    public void set(String characteristicName, Object value, boolean forced) {
       //...
    }
}

set上の方法ObjectContextDecoratorとはObjectContext非常にsimillarです。次のサンプルコードを考えてみます。

ComponentBase base = new ComponentBase();
base.set(""OTM4E_EFFLEVEL"", ""IE1 / STD"", true);

両方のメソッドのシグネチャは、正しく呼び出されているものに適合します。コードではないため、メソッドのシグネチャを変更できません。

コンパイラーは、どのメソッドを呼び出すつもりだったかをどのようにして知るのですか?

IDEで実際に呼び出すメソッドを指摘できることは知っていますが、この状況では、クラスローダーを使用して、サンプルコードを含むメソッドを持つクラスをロードしています。


それらは似ていますが異なります-を渡しても曖昧さはありませんString, String, boolean。最も具体的なメソッドが呼び出されます。これはすべてJLSにあります。
デイブニュートン

最も具体的なものはどれですか。私の理解では、どちらも同じように具体的です。
ガブリエルロバイナ

3
JLS§15.12.2。を参照してくださいコンパイル時の手順2:メソッドのシグネチャを決定します。このためのルールが詳細に説明されています。特に15.12.2.5。最も具体的な方法の選択
ザブザード

1
とは言っても、コンパイラとIDEがどちらを呼び出すかを理解できたとしても、ルールは複雑であり、フマーンがそれを理解するのは非常に困難です。そのため、わかりやすくするためにメソッドの1つを名前変更します。
JB Nizet

2
"this"
余談ですが

回答:


2

コンパイラーは、どのメソッドを呼び出すつもりだったかをどのようにして知るのですか?

引数をチェックし、JLS§15.2で説明されているルールに従って、どちらがより具体的かを判断します。

あなたの場合、電話は:

base.set("OTM4E_EFFLEVEL", "IE1 / STD", true)

引数はStringStringboolean

最初のクラスに一致するもの(簡潔にするためにパラメーター名を変更

public class ObjectContext {
    public void set(String s, Object o, boolean b){
       //...
    }
}

3番目のパラメーターが:であるため、2番目のクラスは呼び出されませんObject

public class ObjectContextDecorator extends ObjectContext {

    public void set(String s, String ss, Object thisOneRightHere) {
        //...
    }
}

ブール値trueはオートボックス化されている場合は一致しますが、最初の値はより具体的です。ここで適用されているルールは次のとおりです。

最初のフェーズ(15.12.2.2)は、ボックス化またはボックス化解除の変換許可せずに過負荷解決実行します

ただし、たとえば、Boolean署名でオブジェクトラッパーを使用する場合は、次のようになります。

public class ObjectContext {
    public void set(String s, Object o, Boolean b){ //<-- third param changed from boolean to Boolean
       //...
    }
}

その後、両方が一致し、コンパイラーは次のメッセージで通知します。

> A.java:25: error: reference to set is ambiguous
>     base.set("OTM4E_EFFLEVEL", "IE1 / STD", true);
>         ^   both method set(String,Object,Boolean) in ObjectContext and method set(String,String,Object) in ObjectContextDecorator match

しかし、あなたの例ではそうではありません。


4

これはすべてJLS§15.2メソッド呼び出し式で説明されています。それは、呼び出す正しいメソッドがどのように選択されるかについてすべてを教えてくれます。また、これは常に成功するとは限りません。

特定のケースでは、2つのメソッドは相互のオーバーロードであるため、§15.2.2「コンパイル時の手順2:メソッドシグネチャの決定」が適用されます-呼び出すオーバーロードはコンパイル時に決定されます。このステップはさらに3つのフェーズに分かれています。

最初のフェーズ(§15.12.2.2)は、ボックス化またはボックス化解除の変換、または可変アリティメソッドの呼び出しの使用を許可せずに過負荷解決を実行します。このフェーズ中に該当するメソッドが見つからない場合、処理は第2フェーズに進みます。

最初のフェーズでは、コンパイラーはボックス化変換を許可せずに適用可能なメソッドを見つけようとします。あなたの場合、を受け取るオーバーロードを呼び出すには、を型Objectに変換するためのボクシング変換が必要です。これにより、最初のフェーズでオーバーロードが選択されなくなります。boolean trueObject

厳密な呼び出しによって適用可能なメソッドが見つからない場合、適用可能なメソッドの検索はフェーズ2(§15.12.2.3)から続行されます。

それ以外の場合は、厳密な呼び出しで適用できるメソッドの中から最も具体的なメソッド(§15.12.2.5)が選択されます。

さて、私たち 1つの方法見つけたので、その方法を選択します。あいまいさはありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.