퀴즈에서이 질문을 보았습니다.
public class MoneyCalc {
public void method(Object o) {
System.out.println("Object Verion");
}
public void method(String s) {
System.out.println("String Version");
}
public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}
이 프로그램의 출력은 “String Version”입니다. 하지만 오버로드 된 메서드에 null을 전달하여 문자열 버전을 선택한 이유를 이해할 수 없었습니다. null은 아무것도 가리키는 문자열 변수입니까?
그러나 코드가 다음과 같이 변경되면
public class MoneyCalc {
public void method(StringBuffer sb) {
System.out.println("StringBuffer Verion");
}
public void method(String s) {
System.out.println("String Version");
}
public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}
“Method (StringBuffer) 메소드가 MoneyCalc 유형에 대해 모호합니다.”라는 컴파일 오류를 제공합니다.
답변
null은 아무것도 가리키는 문자열 변수입니까?
널 참조는 모든 클래스 유형의 표현식으로 변환 될 수 있습니다. 따라서의 경우 String
괜찮습니다.
String x = null;
여기서 String
오버로드 는 JLS의 섹션 15.12.2.5에 따라 Java 컴파일러가 가장 구체적인 오버로드를 선택하기 때문에 선택 됩니다. 특히:
비공식적 인 직관은 첫 번째 메서드가 처리 한 호출이 컴파일 타임 유형 오류없이 다른 메서드에 전달 될 수있는 경우 한 메서드가 다른 메서드보다 더 구체적이라는 것입니다.
두 번째 경우에는 두 방법 모두 여전히 적용 가능하지만 다른 방법보다 더 구체적이 String
지도 않고 StringBuffer
특정 방법도 다른 방법보다 구체적이지 않으므로 컴파일러 오류가 발생합니다.
답변
또한 JLS 3.10.7 은 “null”이 “null 유형”의 리터럴 값임을 선언합니다. 따라서 “null”이라는 유형이 있습니다.
나중에 JLS 4.1 에서는 변수 선언이 불가능한 null 유형이 있지만 null 리터럴을 통해서만 사용할 수 있다고 명시합니다. 나중에 다음과 같이 말합니다.
널 참조는 항상 모든 참조 유형으로 확장 참조 변환을 수행 할 수 있습니다.
컴파일러가 String으로 확장하기로 선택한 이유는 Jon의 답변 에서 설명 할 수 있습니다 .
답변
당신은 할당 할 수 있습니다 string
A를 null
객체에 다음이 유효하고 자바와 대부분의 프로그래밍 언어에 대한 순서가 가장 가까운 유형에 적합하고, 그래서 값.
답변
제목에있는 질문에 대답하려면 null
은 (는) String
이거나이거나에 대한 Object
참조를 할당 할 수 있습니다.null
.
사실이 코드가 컴파일된다는 사실에 놀랐습니다. 이전에 비슷한 것을 시도했는데 호출이 모호하다는 컴파일러 오류가 발생했습니다.
그러나이 경우 컴파일러는 먹이 사슬에서 가장 낮은 방법을 선택하는 것 같습니다. 당신을 돕기 위해 가장 일반적인 버전의 메소드를 원한다고 가정합니다.
그래도이 (겉보기에) 똑같은 시나리오에서 컴파일러 오류가 발생한 예를 찾아 볼 수 있는지 확인해야합니다 …]
편집 : 알겠습니다 . 내가 만든 버전에서는 a String
와 Integer
. 이 시나리오에서는 “가장 구체적인”매개 변수 (및에서 Object
와 같이 String
)가 없으므로 코드에서와 달리 둘 중에서 선택할 수 없습니다.
아주 멋진 질문입니다!
답변
문자열 유형은 객체 유형보다 더 구체적입니다. Integer 유형을 취하는 메서드를 하나 더 추가한다고 가정 해 보겠습니다.
public void method(Integer i) {
System.out.println("Integer Version");
}
그러면 호출이 모호하다는 컴파일러 오류가 발생합니다. 이제 우리는 동일한 우선 순위를 가진 동일하게 구체적인 두 가지 방법을 사용합니다.
답변
Java 컴파일러는 대부분의 파생 클래스 유형을 제공하여 널을 할당합니다.
이를 이해하는 예는 다음과 같습니다.
class A{
public void methodA(){
System.out.println("Hello methodA");
}
}
class B extends A{
public void methodB(){
System.out.println("Hello methodB");
}
}
class C{
public void methodC(){
System.out.println("Hello methodC");
}
}
public class MyTest {
public static void fun(B Obj){
System.out.println("B Class.");
}
public static void fun(A Obj){
System.out.println("A Class.");
}
public static void main(String[] args) {
fun(null);
}
}
출력 : B 클래스.
반면에 :
public class MyTest {
public static void fun(C Obj){
System.out.println("B Class.");
}
public static void fun(A Obj){
System.out.println("A Class.");
}
public static void main(String[] args) {
fun(null);
}
}
결과 : fun (C) 메소드는 MyTest 유형에 대해 모호합니다.
이 사례를 더 잘 이해하는 데 도움이되기를 바랍니다.
답변
출처 : https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5
개념 : 가장 구체적인 방법
설명 : 둘 이상의 구성원 메서드에 액세스 할 수 있고 메서드 호출에 적용 할 수있는 경우 런타임 메서드 디스패치를위한 설명자를 제공 할 하나를 선택해야합니다. Java 프로그래밍 언어는 가장 구체적인 방법이 선택되는 규칙을 사용합니다. null을 특정 유형으로 캐스팅하면 원하는 메서드가 자동으로 호출됩니다.
