다음 클래스가 있다고 가정합니다.
class A {
void recursive(int i) {
System.out.println("A.recursive(" + i + ")");
if (i > 0) {
recursive(i - 1);
}
}
}
class B extends A {
void recursive(int i) {
System.out.println("B.recursive(" + i + ")");
super.recursive(i + 1);
}
}
이제 recursive
클래스 A를 호출합니다 .
public class Demo {
public static void main(String[] args) {
A a = new A();
a.recursive(10);
}
}
출력은 예상대로 10에서 카운트 다운됩니다.
A.recursive(10)
A.recursive(9)
A.recursive(8)
A.recursive(7)
A.recursive(6)
A.recursive(5)
A.recursive(4)
A.recursive(3)
A.recursive(2)
A.recursive(1)
A.recursive(0)
혼란스러운 부분을 살펴 보겠습니다. 이제 우리 recursive
는 클래스 B를 호출합니다 .
예상 :
B.recursive(10)
A.recursive(11)
A.recursive(10)
A.recursive(9)
A.recursive(8)
A.recursive(7)
A.recursive(6)
A.recursive(5)
A.recursive(4)
A.recursive(3)
A.recursive(2)
A.recursive(1)
A.recursive(0)
실제 :
B.recursive(10)
A.recursive(11)
B.recursive(10)
A.recursive(11)
B.recursive(10)
A.recursive(11)
B.recursive(10)
..infinite loop...
어떻게 이런 일이 발생합니까? 이것이 고안된 예라는 것을 알고 있지만 궁금해합니다.
구체적인 사용 사례 가있는 이전 질문입니다 .
답변
이것은 예상됩니다. 이것은의 인스턴스에 대해 발생합니다 B
.
class A {
void recursive(int i) { // <-- 3. this gets called
System.out.println("A.recursive(" + i + ")");
if (i > 0) {
recursive(i - 1); // <-- 4. this calls the overriden "recursive" method in class B, going back to 1.
}
}
}
class B extends A {
void recursive(int i) { // <-- 1. this gets called
System.out.println("B.recursive(" + i + ")");
super.recursive(i + 1); // <-- 2. this calls the "recursive" method of the parent class
}
}
따라서 호출은 A
과 사이에서 번갈아 가며 나타납니다 B
.
A
재정의 된 메서드가 호출되지 않기 때문에 인스턴스의 경우에는 발생하지 않습니다 .
답변
때문에 recursive(i - 1);
In이 A
참조하는 this.recursive(i - 1);
인 B#recursive
두 번째 경우. 그래서, super
및 this
호출 할 것이다 재귀 함수를 다른 방법 .
void recursive(int i) {
System.out.println("B.recursive(" + i + ")");
super.recursive(i + 1);//Method of A will be called
}
에 A
void recursive(int i) {
System.out.println("A.recursive(" + i + ")");
if (i > 0) {
this.recursive(i - 1);// call B#recursive
}
}
답변
다른 답변은 모두 인스턴스 메서드가 재정의되면 재정의 된 상태로 유지되고을 제외하고 다시 가져올 수 없다는 본질적인 요점을 모두 설명했습니다 super
. B.recursive()
를 호출합니다 A.recursive()
. A.recursive()
그런 다음를 호출 recursive()
하여 B
. 그리고 우리는 우주가 끝날 때까지 앞뒤로 탁구를합니다 StackOverflowError
.
하나 쓸 수 있다면 좋은 일 것입니다 this.recursive(i-1)
있는 A
자신의 구현을 얻을 수 있지만, 아마 그래서 일을 중단하고 다른 불행한 결과를 초래할 것 this.recursive(i-1)
에 A
원용하는 B.recursive()
등.
예상되는 동작을 얻을 수있는 방법이 있지만 선견지명이 필요합니다. 즉, super.recursive()
의 하위 유형에있는 a A
가 A
구현 에서 트랩 되기를 원한다는 것을 미리 알아야합니다 . 다음과 같이 수행됩니다.
class A {
void recursive(int i) {
doRecursive(i);
}
private void doRecursive(int i) {
System.out.println("A.recursive(" + i + ")");
if (i > 0) {
doRecursive(i - 1);
}
}
}
class B extends A {
void recursive(int i) {
System.out.println("B.recursive(" + i + ")");
super.recursive(i + 1);
}
}
를 A.recursive()
호출 doRecursive()
하고 doRecursive()
재정의 할 수 없기 때문에 A
자체 논리를 호출하고 있음을 확신합니다.
답변
super.recursive(i + 1);
in class B
는 명시 적으로 슈퍼 클래스의 메서드를 호출하므로 recursive
of A
는 한 번 호출됩니다.
그런 다음 recursive(i - 1);
클래스 A recursive
에서 클래스 의 인스턴스에서 실행되기 때문에 클래스 B
를 재정의 recursive
하는 클래스 의 메서드를 호출합니다 .A
B
그런 다음 B
‘s recursive
는 A
‘s를 recursive
명시 적으로 호출 합니다.
답변
그것은 실제로 다른 방법으로 갈 수 없습니다.
를 호출 B.recursive(10);
하면 인쇄 B.recursive(10)
한 다음 A
with 에서이 메서드의 구현을 호출합니다 i+1
.
당신이 전화 그래서 A.recursive(11)
, 어떤 인쇄 A.recursive(11)
부르는 recursive(i-1);
것입니다 현재 인스턴스에 대한 방법 B
입력 매개 변수를 i-1
가 호출 그래서 B.recursive(10)
다음과 슈퍼 구현 호출 i+1
입니다 11
재귀 적으로 현재 인스턴스의 재귀 호출 i-1
인을 10
, 당신은거야 여기 보이는 루프를 얻으십시오.
이것은 슈퍼 클래스에서 인스턴스의 메서드를 호출하는 경우 호출하는 인스턴스의 구현을 계속 호출하기 때문입니다.
이것을 상상해보십시오.
public abstract class Animal {
public Animal() {
makeSound();
}
public abstract void makeSound();
}
public class Dog extends Animal {
public Dog() {
super(); //implicitly called
}
@Override
public void makeSound() {
System.out.println("BARK");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
“이 인스턴스에서 추상 메서드를 호출 할 수 없습니다”와 같은 컴파일 오류 대신 “BARK”가 표시 AbstractMethodError
되거나 런타임 오류 또는 pure virtual method call
이와 유사한 오류가 발생 합니다. 그래서 이것은 다형성 을 지원하기위한 것 입니다.
답변
B
인스턴스의 recursive
메서드가 super
클래스 구현을 호출 할 때 작동되는 인스턴스 는 여전히입니다 B
. 따라서 슈퍼 클래스의 구현이 recursive
추가 자격없이 호출 될 때 이것이 하위 클래스 구현 입니다. 결과는 당신이보고있는 끝없는 루프입니다.