rau*_*ach 84 java recursion inheritance
假设我们有以下类:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在让我们recursive在A班打电话:
public class Demo {
public static void main(String[] args) {
A a = new A();
a.recursive(10);
}
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,输出从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)
Run Code Online (Sandbox Code Playgroud)
让我们来看看令人困惑的部分.现在我们打电话给recursiveB班.
预期:
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)
Run Code Online (Sandbox Code Playgroud)
实际:
B.recursive(10)
A.recursive(11)
B.recursive(10)
A.recursive(11)
B.recursive(10)
A.recursive(11)
B.recursive(10)
..infinite loop...
Run Code Online (Sandbox Code Playgroud)
这是怎么发生的?我知道这是一个设计的例子,但它让我很奇怪.
具体用例的旧问题.
Tun*_*aki 75
这是预料之中的.这是一个实例发生的事情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
}
}
Run Code Online (Sandbox Code Playgroud)
因此,呼叫在A和之间交替B.
在实例的情况下不会发生这种情况,A因为不会调用overriden方法.
Cod*_*roc 29
因为recursive(i - 1);在第二种情况下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
}
Run Code Online (Sandbox Code Playgroud)
在 A
void recursive(int i) {
System.out.println("A.recursive(" + i + ")");
if (i > 0) {
this.recursive(i - 1);// call B#recursive
}
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*rom 27
其他答案都解释了基本点,一旦实例方法被覆盖,它就会被覆盖,并且除了通过之外没有得到它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.它是这样完成的:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
由于A.recursive()调用doRecursive()并且doRecursive()永远不会被覆盖,因此A可以确保它调用自己的逻辑.
Era*_*ran 16
super.recursive(i + 1);在类B调用父类的方法明确,所以recursive中A被调用一次.
然后,recursive(i - 1);在类A中将调用recursive类B中覆盖recursive类的方法A,因为它是在类的实例上执行的B.
随后B的recursive会叫A的recursive明确,等等.
Epi*_*rce 16
这实际上不能采取任何其他方式.
当你打电话B.recursive(10);,然后打印B.recursive(10)然后调用此方法的实现A用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();
}
}
Run Code Online (Sandbox Code Playgroud)
您将获得"BARK"而不是编译错误,例如"无法在此实例上调用抽象方法"或运行时错误AbstractMethodError甚至pure virtual method call或类似的东西.所以这一切都是为了支持多态性.
jon*_*rpe 14
当B实例的recursive方法调用super类实现时,正在执行的实例仍然是B.因此,当超类的实现在recursive没有进一步限定的情况下调用时,那就是子类实现.结果就是你所看到的永无止境的循环.
| 归档时间: |
|
| 查看次数: |
4391 次 |
| 最近记录: |