나는이 발췌 문장을 우연히 발견했다.
public class ParamTest {
public static void printSum(int a, double b) {
System.out.println("In intDBL " + (a + b));
}
public static void printSum(long a, long b) {
System.out.println("In long " + (a + b));
}
public static void printSum(double a, long b) {
System.out.println("In doubleLONG " + (a + b));
}
public static void main(String[] args) {
printSum(1, 2);
}
}
컴파일 오류가 발생합니다.
오류 : (15, 9) java : printSum에 대한 참조가 ParamTest의 printSum (int, double) 메소드와 ParamTest 일치의 printSum (long, long) 메소드 모두 모호합니다.
이것은 어떻게 모호합니까? 이 경우 첫 번째 매개 변수가 이미 int이므로 두 번째 매개 변수 만 승격시켜야합니까? 이 경우 첫 번째 매개 변수를 승격시킬 필요가 없습니까?
다른 방법을 추가하기 위해 코드를 업데이트하면 컴파일이 성공합니다.
public static void printSum(int a, long b) {
System.out.println(String.format("%s, %s ", a, b));
}
명확히하기 위해 확장하겠습니다. 아래 코드는 애매 모호합니다.
public class ParamTest {
public static void printSum(int a, double b) {
System.out.println("In intDBL " + (a + b));
}
public static void printSum(long a, long b) {
System.out.println("In long " + (a + b));
}
public static void main(String[] args) {
printSum(1, 2);
}
}
그런 다음이 코드는 아래 도 모호한 결과 :
public class ParamTest {
public static void printSum(int a, double b) {
System.out.println("In intDBL " + (a + b));
}
public static void printSum(double a, long b) {
System.out.println("In doubleLONG " + (a + b));
}
public static void main(String[] args) {
printSum(1, 2);
}
}
그러나 이것은 모호성을 초래 하지 않습니다 .
public class ParamTest {
public static void printSum(int a, double b) {
System.out.println("In intDBL " + (a + b));
}
public static void printSum(long a, double b) {
System.out.println("In longDBL " + (a + b));
}
public static void main(String[] args) {
printSum(1, 2);
}
}
답변
나는 이것이 15.12.2.5 에 관한 JLS의 특정 규칙과 관련이 있다고 생각합니다 . 가장 구체적인 방법 선택 . 그 내용은 다음과 같습니다.
둘 이상의 멤버 메소드가 액세스 가능하고 메소드 호출에 적용 가능한 경우, 런타임 메소드 디스패치에 대한 설명자를 제공 할 멤버를 선택해야합니다. Java 프로그래밍 언어는 가장 구체적인 방법을 선택한다는 규칙을 사용합니다.
Java가 가장 구체적인 방법을 선택하는 방법 은 다음 텍스트에 자세히 설명되어 있습니다.
비공식적 인 직관은 첫 번째 방법으로 처리 된 호출이 컴파일 타임 오류없이 다른 방법으로 전달 될 수있는 경우 한 방법이 다른 방법보다 더 구체적이라는 것입니다. 명시 적으로 유형이 지정된 람다 식 인수 (§15.27.1) 또는 변수 arity 호출 (§15.12.2.4)과 같은 경우, 하나의 서명을 다른 서명에 적용 할 수있는 유연성이 있습니다.
예제의 경우 모든 메소드에 액세스하여 메소드 호출에 적용 할 수 있으므로 Java가 가장 구체적인 메소드를 결정해야합니다 .
이러한 방법의 경우 더 구체적으로 결정할 수있는 것은 없습니다.
public static void printSum(int a, double b) {
System.out.println("In intDBL " + (a + b));
} // int, double cannot be passed to long, long or double, long without error
public static void printSum(long a, long b) {
System.out.println("In long " + (a + b));
} // long , long cannot be passed to int, double or double, long without error
public static void printSum(double a, long b) {
System.out.println("In doubleLONG " + (a + b));
} // double, long cannot be passed to int, double or long, long without error
네 번째 방법은 가장 구체적으로 필요한 조건을 충족시키기 때문에 모호성을 정확하게 제거합니다 .
public static void printSum(int a, long b) {
System.out.println(String.format("%s, %s ", a, b));
}
즉, (int, long)은 컴파일 오류없이 (int, double), (long, long) 또는 (double, long)으로 전달 될 수 있습니다.
답변
실제로 매우 흥미로운 질문입니다. Java 언어 사양을 단계별로 살펴 보겠습니다.
-
컴파일러가 잠재적으로 적용 가능한 메소드를 식별하려고 할 때 가장 먼저 수행하는 작업은 Strict Invocation에서 적용 가능한 메소드를 검색하는 것 입니다.
-
귀하의 경우 그러한 방법이 없으므로 다음 단계는 Loose Invocation에서 적용 가능한 방법 을 찾는 것입니다
-
이 시점에서 모든 메소드가 일치하므로 느슨한 호출로 적용 가능한 메소드 중에서 가장 구체적인 메소드 ( §15.12.2.5 )가 선택됩니다.
이것은 중요한 순간이므로 이것을 자세히 살펴 보겠습니다.
다음 중 하나에 해당하는 경우 인수 표현식 e1, …, ek를 사용하여 호출하는 경우 적용 가능한 하나의 메소드 m1이 다른 적용 가능한 메소드 m2보다 더 구체적입니다.
(다음과 같은 경우에만 관심이 있습니다) :
- m2는 일반이 아니며 m1 및 m2는 엄격하거나 느슨한 호출로 적용 가능하며 m1에 형식 매개 변수 유형 S1, …, Sn 및 m2가 형식 매개 변수 유형 T1, …, Tn을 갖는 경우 Si 유형이 더 많습니다 모든 i에 대해 인수 ei에 대해 Ti에 특정 적입니다 (1 ≤ i ≤ n, n = k).
간단히 말해서, 모든 매개 변수 유형이 더 구체적 이면 메소드가 더 구체적 입니다. 과
S <: T ( §4.10 ) 인 경우 S 유형은 모든 표현식에 대해 T 유형보다 더 구체적 입니다.
식은 의 하위 유형 S <: T
임을 의미합니다 . 프리미티브의 경우 다음 관계가 있습니다.S
T
double > float > long > int
따라서 여러분의 방법을 살펴보고 어떤 방법이 다른 방법보다 더 구체적인지 살펴 보겠습니다.
public static void printSum(int a, double b) { // method 1
System.out.println("In intDBL " + (a + b));
}
public static void printSum(double a, long b) { // method 2
System.out.println("In doubleLONG " + (a + b));
}
이 예제에서 메소드 1의 첫 번째 매개 변수는 분명히 메소드 2의 첫 번째 매개 변수보다 더 구체적입니다 (정수 값으로 호출하는 경우 🙂 printSum(1, 2)
. 그러나 두 번째 매개 변수는 방법이 더 특이 하기 때문에 long < double
. 따라서이 방법들 중 어느 것도 다른 것보다 더 구체적인 것은 없습니다. 그렇기 때문에 여기에 모호성이 있습니다.
다음 예에서
public static void printSum(int a, double b) { // method 1
System.out.println("In intDBL " + (a + b));
}
public static void printSum(long a, double b) { // method 2
System.out.println("In longDBL " + (a + b));
}
방법 1의 첫 번째 매개 변수 유형은 방법 2의 매개 변수 유형보다 더 구체적입니다 int < long
. 두 번째 매개 변수 유형이 두 유형 모두 동일하기 때문에 방법 1이 선택되는 이유입니다.
답변
int 값은 Java에서 double로 간주 될 수 있기 때문입니다. 의미 double a = 3
는 유효하고 길다. long b = 3
그래서 모호함을 만드는 이유이다. 당신은 전화
printSum(1, 2);
이 세 가지가 모두 유효하기 때문에 세 가지 방법 모두에 대해 혼란스러워합니다.
int a = 1;
double b =1;
long c = 1;
L을 끝에 두어 긴 값을 지정할 수 있습니다. 예를 들면 다음과 같습니다.
printSum(1L, 2L);
두 배로 변환해야합니다.
printSum((double)1, 2L);
@Erwin Bolwidt의 의견도 읽으십시오