35

この質問に従って、あいまいなオーバーロードされたコンストラクターから選択しようとすると、Java は「最も具体的な」オプションを選択します。この例では:

public class Test{
    private Test(Map map){
        System.out.println("Map");
    }
    private Test(Object o){
        System.out.println("Object");
    }
    public static void main(String[] args){
        new Test(null);
    }
}

それは印刷されます

"地図"

ただし、「最も具体的」とはどういう意味かを正確に理解しようとしていました。「可能な限り少ないタイプを参照する可能性がある」のように、「あいまいさを最小限に抑える」ことを意味すると思いました。このコンテキストでObjectは、 はプリミティブではないものである可能性がありますが、 またはMapのみである可能性があります。基本的に、継承ツリーのリーフに近いクラスが選択されると想定していました。これは、あるクラスが他のクラスのサブクラスである場合に機能します。Map? extends Map

public class Test{
    private Test(A a){
        System.out.println("A");
    }
    private Test(B b){
        System.out.println("B");
    }
    public static void main(String[] args){
        new Test(null);
    }
}

class A{}

class B extends A{}

"B"

それから私はこれを思いついた:

public class Test{
    private Test(A a){
        System.out.println("A");
    }
    private Test(E e){
        System.out.println("E");
    }
    public static void main(String[] args){
        new Test(null);
    }
}

class A{}

class B extends A{}

class C{}

class D extends C{}

class E extends D{}

既知の 1 つのタイプのみを参照する可能性があるのに対し、2 つの (および) を参照する可能性があるためE、出力する必要があると思います。しかし、あいまいな参照エラーが発生します。EAAB

実際にコンストラクターを選択する方法は? 私はドキュメントを読みましたが、率直に言って、それが特異性をどのように決定するかを完全に理解できませんでした. Eより具体的であると判断できない理由の正確な説明を期待していAます。

4

3 に答える 3

45

これは、パラメーターの型に変換できる型の数に基づいているのではなく、暗黙的な変換により、あるオーバーロードで有効な値が別のオーバーロードで有効かどうかに基づいています。

たとえば、 からStringへの暗黙的な変換Objectがありますが、その逆は当てはまらないため、Stringは よりも具体的ですObject

B同様に、 からへの暗黙の変換Aがありますが、その逆は当てはまらないため、Bは よりも具体的ですA

ただし、 と を使用するAE、どちらも他方より具体的ではありません。 から への変換も、 からへのA変換もありません。そのため、オーバーロードの解決が失敗します。EEA

JLS の関連ビットは、実際には15.12.2.5であり、これにはこれが含まれているため、理解しやすくなります。

非公式の直観は、最初のメソッドによって処理された呼び出しがコンパイル時エラーなしで別のメソッドに渡される場合、あるメソッドは別のメソッドよりも具体的であるということです。

あなたが持っている場合:

void foo(String x)
void foo(Object x)

によって処理されるすべての呼び出しは によって処理foo(String)できますがfoo(Object)、その逆は当てはまりません。(たとえば、 を呼び出すことができ、foo(new Object())では処理できませんでしたfoo(String)。)

于 2016-08-16T16:25:03.667 に答える
9

JSL§15.12.2.5の次のステートメントは、次のように答えています。

非公式の直観は、最初のメソッドによって処理された呼び出しがコンパイル時エラーなしで別のメソッドに渡される場合、あるメソッドは別のメソッドよりも具体的であるということです。

ケース1

  • 最初のコンストラクターObject以外のものを渡すことはできませんが、コンストラクターには何でも渡すことができます。Mapしたがって、コンストラクターで渡すものは何でもMapコンストラクターで処理できるためObjectTest(Map map)モート固有になります。

ケース 2

  • BextendsであるためA、ここではTest(B b)コンストラクターがより具体的になります。継承BTest(A a)おかげで渡すことができるので。

ケース 3

  • この場合、より具体的な方法を表すための直接的な変換は行われず、あいまいさが生じます。
于 2016-08-16T16:25:25.373 に答える
6

この動作は、E が A よりも具体的ではないためです。これらは異なる階層に属しており、比較することはできません。したがって、null を渡すと、Java は使用する階層を認識できません。

于 2016-08-16T16:24:53.700 に答える