Java动态绑定

时间:2009-03-16 00:51:33

标签: 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 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

前几个是好的,但后来我真的不明白。 有没有人对这个问题有很好的解释?

由于

3 个答案:

答案 0 :(得分:5)

我首先要绘制一张图片......

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

然后我会跟踪变量:

  • Larry - stooge1 - >卷曲
  • Moe - stooge2 - >拉里
  • Moe - stooge3 - >卷曲
  • Curly - stooge4 - >卷曲
  • Larry - stooge5 - >拉里

  • stooge1.print(new Moe())

    • stooge1 - > Curly所以调用Curly.print(Moe)
  • ((Curly)stooge1).print(new Larry());

    • stooge1 - > Curly所以调用Curly.print(new Larry())
  • ((Larry)stooge2).print(new Moe());

    • stooge2 - > Larry所谓的Larry.print(新的Moe());
  • stooge2.print(new Curly());
    好吧,这是有点棘手的地方(对不起,我在此之前停了一个)

    • stooge2被宣布为Moe。因此,当编译器查看要调用的内容时,它将调用print(Moe)方法。然后在运行时它知道stooge2是Larry所以它调用了Larry.print(Moe)方法。

等...

让我知道如果一直跟着这一切并不适合你。

(更新以澄清下一个)

所以一般规则是:

  • 编译器查看变量类型以决定调用哪种方法。
  • 运行时查看变量指向的实际类,以决定从何处获取方法。

所以当你有:

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

编译器说:

  • 拉里可以被分配到stooge2吗? (是的,因为Larry是Moe的子类)
  • Moe有印刷(Moe)方法吗? (是)

运行时说:

  • 我应该在这个对象上调用print(Moe)方法... stooge2
  • stooge2指向拉里。
  • 我将在Larry课程中调用print(Moe)方法。

一旦你完成了所有这些工作,试着去掉一些方法,看看它是如何改变的。

答案 1 :(得分:2)

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

TofuBeer提到的一般规则只适用于动态绑定案例。在静态绑定中,决策仅在编译时进行。

您的示例混合了动态绑定(当方法被覆盖时)和静态绑定(当方法被重载时)。

查看at this question了解更多详情。

答案 2 :(得分:0)

提示是在查看对象时忽略左侧的值。相反,在声明期间查看右边的值,这是对象的实际值。