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

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

前面几个还好,后面就实在看不懂了。有人对这个问题有很好的解释吗?

谢谢

有帮助吗?

解决方案

我会从画一幅画开始......

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

然后我会跟踪变量:

  • 拉里 - 傀儡1 -> 卷毛
  • Moe - 傀儡2 -> 拉里
  • 萌 - 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) 方法。

ETC...

如果一直遵循这一点对您来说不成功,请告诉我。

(更新以澄清下一个)

所以一般规则是:

  • 编译器查看变量类型来决定调用什么方法。
  • 运行时查看变量指向的实际类来决定从哪里获取方法。

所以当你有:

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

编译器说:

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

运行时说:

  • 我应该在这个对象上调用 print(Moe) 方法......傀儡2
  • stooge2 指着 Larry。
  • 我将调用 Larry 类中的 print(Moe) 方法。

一旦你完成了所有这些工作,尝试摆脱一些方法,看看这会如何改变事情。

其他提示

其实,这个问题并不像看起来那么简单,因为Java是静态和动态绑定。你必须了解每个应用之前,你会明白你是从这项工作取得的成果。

通过TofuBeer提到的一般规则是仅在动态绑定的情况下是正确的。在静态绑定,决定仅在编译时由

您例如混合动力结合(当方法被覆盖)和静态结合(当方法被过载)。

看看了解更多细节,这个问题

一个提示是在看物体时忽略左侧的值。相反,看的声明中右侧的值,这是该对象的实际值。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top