13
class Another {
    public void method(Object o) {
        System.out.println("This is in method which takes object");
    }
    public void method(String s) {
        System.out.println("This is method which takes string");
    }
}

public class NewClass {
    public static void main(String args[]) {
        Another an = new Another();
        an.method(null);
    }
}

これを実行しようとすると、

これは文字列を取るメソッドです

出力として。なぜ「これはオブジェクトを取るメソッドにある」ではないのですか? オブジェクトも null にすることも、文字列も null にすることもできます。最初のメソッドを呼び出さないのはなぜですか?

4

4 に答える 4

25

Java 言語仕様によると、両方のメソッドが提供された引数を処理できるオーバーロードされたメソッドの場合、より具体的な引数を持つメソッドが選択されます。は( extends )Stringよりも具体的であるため、が選択されて呼び出されます。ObjectStringObjectvoid method(String)

于 2010-06-14T12:54:27.500 に答える
7

これは、JLS で指定されているとおりです。

JLS 15.12.2.5 最も具体的な方法の選択

複数のメンバー メソッドがアクセス可能で、メソッド呼び出しに適用できる場合は、ランタイム メソッド ディスパッチの記述子を提供するために 1 つを選択する必要があります。Java プログラミング言語では、最も具体的な方法が選択されるという規則が使用されます。

AStringは-a ですが、すべてが -a というObjectわけではありません。したがって、はよりも具体的です。したがって、上記の例でオーバーロードが選択されている理由です。ObjectStringStringObjectString


この正確な質問(本質的に) が素晴らしいJava Puzzlers (強く推奨)、特にPuzzle 46: The Case of the Confusing Constructor に登場したことは注目に値します。

Java のオーバーロード解決プロセスは、2 つのフェーズで動作します。最初のフェーズでは、アクセス可能で適用可能なすべてのメソッドまたはコンストラクターを選択します。第 2 段階では、第 1 段階で選択されたメソッドまたはコンストラクターのうち、最も具体的なものを選択します。あるメソッドまたはコンストラクターは、他のメソッドまたはコンストラクターに渡されたパラメーターを受け入れることができる場合、他のものよりも具体的ではありません

このパズルを理解するための鍵は、メソッドまたはコンストラクターが最も具体的なテストでは、実際のパラメーター(呼び出しに表示されるパラメーター)を使用しないということです。それらは、適用可能なオーバーロードを決定するためにのみ使用されます。コンパイラは、適用可能でアクセス可能なオーバーロードを決定すると、正式なパラメーター(宣言に表示されるパラメーター) のみを使用して、最も具体的なオーバーロードを選択します。


締めくくりに、 Effective Java 2nd EditionItem 41: Use overloading judiciouslyから引用します。

どのオーバーロードが選択されるかを決定するルールは非常に複雑です。それらは言語仕様の33ページを占めており、それらの微妙な点をすべて理解しているプログラマーはほとんどいません。

言うまでもなく、この本も非常におすすめです。

こちらもご覧ください


明示的なキャストについて

では、引数を指定してObjectオーバーロードを呼び出すにはどうすればよいでしょうか?null

シンプル:nullを type にキャストしObjectます。これが役立つ/必要なシナリオがいくつかありますが、これはその 1 つです。

たとえば、 ? を取るオーバーロードがある場合はどうなりIntegerますか?

次に、メソッド呼び出しがあいまいで、コンパイル時エラーが発生します。

JLS 15.12.2.5 最も具体的な方法の選択

最も具体的なメソッドが 2 つ以上あるため、最も具体的なメソッドがない可能性があります。この場合 [... いくつかの例外を除いて] メソッド呼び出しがあいまいであると言い、コンパイル時エラーが発生します。

あいまいさを解決するために、null(または他の式) を目的のオーバーロード型にキャストできます。

こちらもご覧ください

于 2010-06-14T13:28:11.843 に答える
5

コンパイラは、オーバーロードされたメソッド呼び出しを解決するときに、可能な限り最も狭い一致を常に見つけます。

ところで、Java の規則では、クラスに大文字の名前を使用しますAnother

于 2010-06-14T12:53:31.433 に答える
1

このような場合、Java 6(Java 5はコンパイラエラーをスローしたと思います)では、nullの属性として最低レベルのクラスを選択することはかなり確信しています。(文字列はオブジェクトであるため、階層の下位にあります)

于 2010-06-14T12:56:01.600 に答える