Java动态绑定

Java动态绑定,java,binding,overloading,method-dispatch,Java,Binding,Overloading,Method Dispatch,我正在练习考试,发现了一个让我完全迷路的样例问题。 对于以下代码,请查找输出内容: 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 voi

我正在练习考试,发现了一个让我完全迷路的样例问题。 对于以下代码,请查找输出内容:

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 卷曲1 卷曲2 拉里1 拉里1 卷曲1 卷曲1 卷曲1 卷曲2 卷发3 卷发3 卷曲1 卷曲2 拉里2 拉里2 拉里1 前几个没问题,但我真的不明白。 有人能很好地解释这个问题吗


谢谢

提示在查看对象时忽略左侧的值。相反,请在声明过程中查看右侧的值,这是对象的实际值。

我将从绘制一张图片开始

Moe - print(Moe)
 |
Larry - print(Moe), print(Larry)
 |
Curly - print(Moe), print(Larry), print(Curly)
然后我会跟踪变量:

  • 拉里-斯托吉1->Curly
  • Moe-stooge2->Larry
  • Moe-stooge3->Curly
  • 卷曲-弯腰4->卷曲
  • 拉里-斯托吉5->拉里

  • stooge1.打印(新Moe())

    • stooge1->Curly so调用Curly.print(Moe)
  • ((卷曲的)凳子1.print(新拉里())

    • stooge1->Curly so调用Curly.print(new Larry())
  • ((Larry)stooge2).print(新Moe())

    • stooge2->Larry这么叫Larry.print(新Moe())
  • stooge2.print(新卷发())
    好的,这是它变得有点棘手的地方(很抱歉我在这里之前停止了一个)

    • stooge2被宣布为教育部。因此,当编译器查看调用什么时,它将调用print(Moe)方法。然后在运行时它知道stooge2是Larry,所以它调用Larry.print(Moe)方法
等等

让我知道,如果你一直这样做不奏效

(更新以澄清下一个问题)

因此,一般规则是:

  • 编译器查看变量类型以决定调用哪个方法
  • 运行时查看变量所指向的实际类,以决定从何处获取方法
因此,当你有:

Moe stooge2 = new Larry();
stooge2.print(new Moe());
编者说:

  • 拉里能被分配到stooge2吗?(是,因为Larry是Moe的一个子类)
  • Moe是否有打印(Moe)方法?(是的)
运行时说:

  • 我应该调用这个对象的print(Moe)方法。。。走狗2
  • stooge2指的是拉里
  • 我将在Larry类中调用print(Moe)方法

一旦你解决了所有这些问题,试着去掉一些方法,看看它们是如何改变的。

实际上,这个问题并不像看上去那么简单,因为Java是静态和动态绑定的。在理解本练习的所有结果之前,您必须了解每个应用的位置

TofuBeer提到的一般规则仅在动态绑定情况下正确。在静态绑定中,决策只在编译时做出

您的示例混合了动态绑定(重写方法时)和静态绑定(重载方法时)


查看更多详细信息。

前3个是直截了当的。如果你能继续下一个3,那会有帮助的。谢谢上面的更改应该会有所帮助。@TofuBeer-不完全正确。在纯动态绑定的情况下,stooge2.print(新的Curly())将打印“Larry 2”而不是“Larry 1”,因为Curly扩展了Larry。(实际上,stooge2.print(new Larry())是一个更好的例子,因为它也会打印“Larry 1”而不是“Larry 2”。这会使错误更加明显。重载方法是静态绑定的,这就是为什么不调用它的原因。因为在这种情况下,该方法是动态绑定的,这只发生在被重写的方法中。是的,stooge2.print(new Larry())将与stooge2.print(new Moe())相同,因为Moe没有打印(Larry)在Java语言中,stooge2.print(new Larry())无法调用Larry.print(Larry)方法。