문제

시험을 위해 연습하고 있는데 완전히 당황하게 만드는 샘플 문제를 발견했습니다.다음 코드의 경우 출력이 무엇인지 확인하세요.

class Moe {
    public void print(Moe p) {
        System.out.println("Moe 1\n");
    }
}
class Larry extends Moe {
    public void print(Moe p) {
        System.out.println("Larry 1\n");
    }
    public void print(Larry l) {
        System.out.println("Larry 2\n");
    }
}
class Curly extends Larry {
    public void print(Moe p) {
        System.out.println("Curly 1\n");
    }
    public void print(Larry l) {
        System.out.println("Curly 2\n");
    }
    public void print(Curly b) {
        System.out.println("Curly 3\n");
    }
}
public class Overloading_Final_Exam {
    public static void main (String [] args) {
        Larry stooge1 = new Curly();
        Moe stooge2 = new Larry();
        Moe stooge3 = new Curly();
        Curly stooge4 = new Curly();
        Larry stooge5 = new Larry();
        stooge1.print(new Moe()); 
        ((Curly)stooge1).print(new Larry()); 
        ((Larry)stooge2).print(new Moe()); 
        stooge2.print(new Curly()); 
        stooge3.print(new Curly()); 
        stooge3.print(new Moe()); 
        stooge3.print(new Larry()); 
        ((Curly)stooge3).print(new Larry()); 
        ((Curly)stooge3).print(new Curly()); 
        stooge4.print(new Curly()); 
        stooge4.print(new Moe()); 
        stooge4.print(new Larry()); 
        stooge5.print(new Curly()); 
        stooge5.print(new Larry()); 
        stooge5.print(new Moe()); 
    }
}

나는 내 생각을 염두에 두었지만 Java를 실행했을 때 완전히 다른 것을 얻었습니다.

Curly 1
Curly 2
Larry 1
Larry 1
Curly 1
Curly 1
Curly 1
Curly 2
Curly 3
Curly 3
Curly 1
Curly 2
Larry 2
Larry 2
Larry 1

처음 몇 개는 괜찮은데 그 다음부터는 정말 이해가 안 돼요.누구든지 이 문제에 대해 좋은 설명을 갖고 있나요?

감사해요

도움이 되었습니까?

해결책

사진을 그리는 것으로 시작하겠습니다 ...

Moe - print(Moe)
 |
Larry - print(Moe), print(Larry)
 |
Curly - print(Moe), print(Larry), print(Curly)

그런 다음 변수를 추적합니다.

  • Larry -Stooge1-> Curly
  • Moe -Stooge2-> Larry
  • Moe -Stooge3-> Curly
  • Curly -Stooge4-> Curly
  • 래리 -Stooge5-> 래리

  • stooge1.print(new Moe())

    • stooge1-> curly so callly.print (moe)
  • ((Curly)stooge1).print(new Larry());

    • stooge1-> curly so kalling curly.print (new larry ())
  • ((Larry)stooge2).print(new Moe());

    • stooge2-> larry so 전화 larry.print (new Moe ());
  • stooge2.print(new Curly());
    좋아, 이것은 조금 까다로워지는 곳입니다 (죄송합니다.

    • Stooge2는 Moe라고 선언됩니다. 따라서 컴파일러가 호출 할 내용을 살펴보면 인쇄 (MOE) 메소드를 호출 할 것입니다. 그런 다음 런타임에 stooge2가 래리라는 것을 알고 있으므로 larry.print (MOE) 메소드를 호출합니다.

등...

그 길을 따라 가면 당신을 위해 문제가되지 않으면 알려주세요.

(다음을 명확히하기 위해 업데이트)

일반적인 규칙은 다음과 같습니다.

  • 컴파일러는 변수 유형을보고 호출 할 방법을 결정합니다.
  • 런타임은 변수가 메소드를 얻을 위치를 결정하기 위해 가리키는 실제 클래스를 살펴 봅니다.

그래서 당신이 가지고있을 때 :

Moe stooge2 = new Larry();
stooge2.print(new Moe());

컴파일러는 말한다 :

  • Larry를 Stooge2에 할당 할 수 있습니까? (예, 래리가 Moe의 서브 클래스이기 때문에)
  • Moe에는 인쇄 (Moe) 방법이 있습니까? (예)

런타임은 다음과 같이 말합니다.

  • 이 객체에서 인쇄 (MOE) 메소드를 호출해야합니다 ... Stooge2
  • stooge2는 래리를 가리킨다.
  • Larry 클래스에서 Print (MOE) 메소드를 호출하겠습니다.

일단 작업 한 후에는 모든 작업을 수행하면 몇 가지 방법을 제거하고 어떻게 변화하는지 확인하십시오.

다른 팁

실제로 이 문제는 보이는 것만큼 간단하지 않습니다. 왜냐하면 Java는 정적이면서도 동적으로 바인딩되기 때문입니다.이 연습에서 얻는 모든 결과를 이해하기 전에 각각이 적용되는 위치를 이해해야 합니다.

TofuBeer가 언급한 일반 규칙은 동적 바인딩의 경우에만 정확합니다.정적 바인딩에서는 컴파일 타임에만 결정이 내려집니다.

예제에서는 동적 바인딩(메서드가 재정의된 경우)과 정적 바인딩(메서드가 오버로드된 경우)을 혼합합니다.

구경하다 이 질문에 상세 사항은.

힌트는 객체를 볼 때 왼쪽의 값을 무시하는 것입니다. 대신, 선언 중에 오른쪽의 값을보십시오. 이것이 객체의 실제 값입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top