Java 遗传、多态性问题

Java 遗传、多态性问题,java,inheritance,polymorphism,overriding,Java,Inheritance,Polymorphism,Overriding,我目前正在学习我的第一个Java课程,我们最近讨论了多态性和继承的主题。为了更好地理解事物是如何工作的,我尝试了一些事情,我想知道是否有人能帮助我理解为什么下面的代码会给我输出,以及当我们结合继承和重写方法时可能出现的问题 public class AClass { public void m1() { System.out.println("A.m1()"); this.m2(); } public void m2() { System.out.println("A.m

我目前正在学习我的第一个Java课程,我们最近讨论了多态性和继承的主题。为了更好地理解事物是如何工作的,我尝试了一些事情,我想知道是否有人能帮助我理解为什么下面的代码会给我输出,以及当我们结合继承和重写方法时可能出现的问题

public class AClass {
public void m1() {
    System.out.println("A.m1()");
    this.m2();
}
public void m2() {
    System.out.println("A.m2()");
}

public static void main(String [] args) {
AClass A = new AClass();
BClass B = new BClass();

A.m1();
A.m2();
B.m1();

public class BClass extends AClass {

@Override
public void m2() {

    // TODO Auto-generated method stub
    System.out.println("B.m2()");
}

}
我得到的结果是:

A.m1()
A.m2()
A.m2()
A.m1()
B.m2()

此外,如果在类B的m2()方法中添加super.m1()调用,则会出现堆栈溢出错误。谁能告诉我为什么会这样?谢谢

你的情况很简单。当您重写父类的方法时,将其实现替换为子类中的
@override
方法。例如,当您调用
B.m1()
时,java监视
Bclass
中的
m1
方法,如果没有找到,则使用与
Aclass
中签名相同的方法。然后它观察
Bclass
中的
m2()
方法,找到一些并调用它

多态性更为复杂。它允许从子类调用相同的方法,而不需要知道这些确切的类。我覆盖了维基百科页面上的一些代码:

abstract class Animal {
    abstract String talk();
}

class Cat extends Animal {
    @Override
    String talk() {
        return "Meow!";
    }
}

class Dog extends Animal {
    @Override
    String talk() {
        return "Woof!";
    }
}

void main() {
    Animal[] animals = new Animal[size];
    //then goes creation
    for (Animal a : animals) {
        a.talk();
    }
}
A.m1()-->打印“A.m1()”,因为您正在从主方法调用此方法

方法也在其内部调用此.m2()。这将进入方法m2()并打印-->“A.m2()”

**注意,这个.m2()与调用m2()是一样的

A.m2()-->打印“A.m2()”,因为您是从主目录调用此方法

现在是稍微棘手的部分

如您所见,BClass没有m1()方法,但它从AClass继承了它。通过从AClass继承,BClass(在内部)拥有AClass的所有公共和受保护的方法。这意味着BClass现在有一个m1()方法(与AClass相同)。因此,调用B.m1()将打印AClass m1()-->“A.m1()”


现在请记住,A.m1()也在其内部调用此.m2()。但由于BClass也有一个m2()方法,Java将使用该方法,这将最终打印-->“B.m2()”

无限递归可以用以下方式解释:

无限递归是由调用B.m1()引起的。类BClass扩展了AClass,因此BClass继承了AClass的公共方法,即方法m1和m2。因此,方法调用B.m1()调用从classA继承的BClass的方法m1。在m1()内部,调用this.m2()实际上相当于B.m2()。因此它从BClass调用被重写的方法m2(),因为被重写的方法比最初在超类中实现的方法具有更高的优先级。但是当调用BClass中的m2时,它反过来调用方法m1()再次通过super.m1()调用AClass的重写方法,然后再次通过this.m2()调用BClass的重写方法。这会导致无限递归

另外,如果我在类B的m2()方法中添加一个super.m1()调用,那么 堆栈溢出错误。谁能告诉我为什么会这样

函数调用在内存中相互叠加。在代码中

public class AClass {
public void m1() {
    System.out.println("A.m1()");
    this.m2();
}
public void m2() {
    System.out.println("A.m2()");
}

public static void main(String [] args) {
    AClass A = new AClass();
    BClass B = new BClass();

    B.m1();
}

public class BClass extends AClass {

@Override
public void m2() {

    // TODO Auto-generated method stub
    System.out.println("B.m2()");
    super.m1();
}

}
您的代码将导致一个永无止境的序列

  • main
    位于堆栈的底部
  • main
    中的语句
    B.m1()
    调用
    m1()
    ,它被推到
    main
    上的堆栈中
  • m1()
    的主体中的语句
    this.m2()
    调用被重写的
    m2()
    ,它被推到堆栈中的
    m1()
  • 被重写的
    m2()
    主体中的语句
    super.m1()
    调用
    m1()
    ,该语句被推到堆栈中的
    m2()
  • 返回步骤3
  • 函数调用被一个一个地推送到堆栈中,没有一个被弹出。这会导致堆栈溢出


    m2
    in
    BClass
    调用
    AClass
    中的
    m1
    ,它调用
    m2
    ,等等(无限递归)。谢谢你的回复,如果你不介意的话,可以一步一步地看一下,就像我不明白为什么我们会有无限递归一样,为什么它会继续运行?调试它并逐步完成代码。谢谢!这是有道理的,但是我仍然不能完全确定为什么程序会崩溃,我不明白为什么我们会进入一个无限循环(当我添加super.m1()方法时)当你在
    B.m2()
    方法的开头添加
    super.m1()
    时,代码是这样的:
    B.m1()
    ->
    A.m1()
    ->
    B.m1()
    ->
    A.m1()
    一次又一次。更详细地说:当调用B.m1()时,将执行A.m1()中的代码,因为尽管类B扩展了类A,但它不会覆盖m1。问题是A.m1()调用m2()(在打印“A.m1()”)之后),它在B中有自己的实现,因此它是被调用的。但是如果你在里面放一个super.m1(),会再次调用a.m1(),“a.m1()”会再次打印,B.m2()会再次调用,依此类推。知道了?