2016-08-16 9 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 일 수 있습니다. 기본적으로 상속 트리의 잎에 더 가까운 클래스가 선택 될 것이라고 생각했습니다.

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은 알려진 유형 중 하나만 참조 할 수 있지만 A은 두 가지를 참조 할 수 있습니다 (AB). 그러나 모호한 참조 오류가 발생합니다.

실제로 생성자를 선택하는 방법은 무엇입니까? 나는 the docs을 읽었지만 솔직히 나는 그것이 어떻게 특이성을 결정 하는지를 따라갈 수 없었다. 내가 왜 EA보다 더 구체적인지를 결정할 수없는 이유에 대한 설명을 기대하고 있습니다.

+3

아무 것도 할 수 없습니다. ***? 문자열을 확장 ***, 문자열 클래스는 최종 –

+0

@ ΦXocę 웃어 Пepeúpa ツ 좋은 지적. 나는 그것을 고치겠다. – ewok

답변

46

암시 적 변환으로 인해 하나의 오버로드에 유효한 값이 다른 값에 유효한지 여부는 매개 변수 유형으로 변환 할 수있는 유형 수에 기반하지 않습니다.

예를 들어 String에서 Object으로의 암시 적 변환이 있지만 그 반대가 사실이 아니므로 StringObject보다 구체적입니다.

은 마찬가지로 B에서 A에 암시 적 변환이, 그러나 반대는 사실이 아니다, 그래서 BA보다 더 구체적이다. 그러나 AE

, 어느 쪽이 다른 쪽보다 더 구체적이다 -이 A에서 E없이 변환 및 A-E에서 변환 없음. 이것이 과부하 해결에 실패한 이유입니다.

JLS의 관련 비트는 실제로 당신이 이해하기 쉽게 만들 수있는 그이 포함 15.12.2.5입니다 :

비공식 직관은 어떤 호출이 처리하는 경우 하나 개의 방법이 다른 것보다 더 구체적입니다입니다 첫 번째 메소드는 컴파일 타임 오류없이 다른 메소드로 전달 될 수 있습니다.

당신이 그렇다면 :

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 답변의 진술에 따라,

비공식 직감 하나 개의 방법보다 더 구체적인 때문이다 또 다른 첫 번째 메서드에서 처리 한 호출이 컴파일 타임 오류없이 다른 하나에 전달 될 수있는 경우 이 전달 될 수 있습니다.

사례 1

  • 우리가 처음 생성자에서 Map 이외의를 통과 할 수있는 동안 당신은 Object 소요 생성자에서 아무것도 전달할 수 있습니다. 따라서 Map 생성자에서 전달하는 내용은 Object 생성자에서 처리 할 수 ​​있으므로 Test(Map map)은 모트 고유가됩니다. B 이후

사례 2

  • Test(B b) 생성자 구체적하게 여기 A 연장된다. B계승 덕분에 에 전달할 수 있으므로입니다. 이 경우

사례 3

  • 은 더욱 구체적인 방법을 묘사하는 직접 변환 없다 그리고 모호함을 초래한다.