2016-08-16 8 views
36

this questionで、あいまいなオーバーロードされたコンストラクタの中から選択しようとすると、Javaは "最も特殊な"オプションを選択します。この例では: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はプリミティブではないものであればよく、MapMapまたは? extends Mapであることがあります。基本的には、継承ツリーの葉に近いクラスが選択されると仮定しました。 1クラスは他のサブクラスである場合には動作します:

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{} 

私はそれを印刷しなければならないと思うだろうEのように、Eは1つの既知のタイプのみを参照することができ、Aは2つを参照することができる(AおよびB)。しかし、あいまいな参照エラーが発生します。

実際にどのようにコンストラクタを選択していますか?私はthe docsを読んだが、率直に言って私はそれが特異性をどのように決定するかをかなり追うことができなかった。 EAより具体的であると判断できない理由を正確に説明したいと考えています。

+3

何もできません:***? String ***、string classはfinalです –

+0

@ΦXocę笑Пepeúpaツー良い点。私はそれを修正します – ewok

答えて

46

パラメータタイプに変換できるタイプの数に基づいていません。暗黙的な変換のために、1つのオーバーロードに有効な値が別のものに対して有効かどうかです。

例えば、StringからObjectへの暗黙の変換がありますが、その逆は真ではありませんので、StringObjectより具体的です。

は同様にBからAへの暗黙の変換がありますが、その逆は真ではありませんので、BAより具体的です。しかしAE

、いずれも他のより特異的である - そこAからEへの変換、およびAからEからNO転化。そのため、オーバーロードの解決に失敗します。

JLSの該当ビットは、実際にあなたが理解しやすいようかもしれないこの含ん15.12.2.5、次のとおりです。

非公式直感がどの呼び出しがで扱う場合は、1つの方法は、別のより具体的であるということですが最初のメソッドは、コンパイル時エラーなしでもう一方のメソッドに渡すことができます。

あなたが持っているのであれば:

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

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

+0

その引用は私が探していたものです。私はこれまでにそれを読まなかったと思う。 – ewok

+3

Javaの過負荷解決はどのようなメトリックを選択するのか "複雑"なんて知っていますか?例えば。 C#のオーバーロードの分解能はNPです。実際、3-SATの問題を一連のオーバーロードでエンコードし、コンパイラで解決することができます。 –

+0

@JörgWMittag:私はまったくわかりません、私は恐れています:( –

6

この現象は、異なる階層に属しているため、EはAよりも具体的ではないため、比較できません。したがって、nullを渡すと、Javaはどの階層を使用するかを知ることができません。

9

を非公式直感一つの方法は、より具体的な以上であることで、

JSL§15.12.2.5回答の声明に続き another 最初のメソッドで処理された呼び出しがコンパイル時エラーなしでもう一方のメソッドに渡される可能性がある場合は、 を渡すことができます。

ケース1

  • 我々は最初のコンストラクタでMap以外を渡すことはできませんしながら、あなたはObjectを取るコンストラクタで何かを渡すことができます。ですから、Mapコンストラクタで渡すものはObjectコンストラクタで処理できるので、Test(Map map)はmote固有になります。

ケース2

  • BAを拡張しているので、ここでTest(B b)コンストラクタは、より具体的になります。 Bの相続のおかげでTest(A a)に渡すことができます。この場合

ケース3

  • は、より具体的な方法を描写する直接変換が存在しないと、それは、曖昧もたらします。
関連する問題