【问题标题】:Java dynamic bindingJava 动态绑定
【发布时间】:2010-10-13 12:43:33
【问题描述】:

我正在练习考试,发现了一个让我完全迷失的示例问题。 对于下面的代码,找出输出是什么:

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 时,我得到了完全不同的东西:

卷曲 1 卷曲 2 拉里 1 拉里 1 卷曲 1 卷曲 1 卷曲 1 卷曲 2 卷曲 3 卷曲 3 卷曲 1 卷曲 2 拉里 2 拉里 2 拉里 1

前几张还可以,后来实在看不懂。 有人对这个问题有很好的解释吗?

谢谢

【问题讨论】:

    标签: java binding overloading method-dispatch


    【解决方案1】:

    我会先画一幅画……

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

    然后我会跟踪变量:

    • Larry - stooge1 -> Curly
    • 萌 - stooge2 -> 拉里
    • 萌 - stooge3 -> 卷毛
    • 卷毛 - stooge4 -> 卷毛
    • 拉里 - 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(new 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 的子类)
    • 萌有打印(萌)方法吗? (是)

    运行时说:

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

    一旦你解决了所有这些问题,请尝试摆脱一些方法,看看它会如何改变事情。

    【讨论】:

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

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

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

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

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

    【讨论】:

      【解决方案3】:

      提示是在查看对象时忽略左侧的值。而是在声明的时候看一下right的值,这是对象的实际值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-26
        • 2022-01-05
        • 1970-01-01
        • 2018-08-27
        • 2010-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多