Java - 静态&动态类型 - “这打印什么?”

时间:2012-06-28 05:14:28

标签: java oop inheritance dynamic static

所以我在理解课堂上展示的这个例子时遇到了一些麻烦 - 它应该说明静态和放大之间的微妙之处。 Java中的动态类型。

public class Piece {

    public static void main (String[] args) {
        Piece p2 = new Knight();
        Knight p1 = new Knight();
        p1.capture(p2); // call 1; "Knight is bored" is supposed to be printed
        p2.capture(p1); // call 2; "knight is bored" is supposed to be printed
    }

    public void capture () {
        System.out.println("Capturing");
    }

    public void capture (Piece p) {
        System.out.println("I'm bored")
    }

public class Knight extends Piece {

    public void capture (Piece p) {
        System.out.println("Knight is bored");
    }

    public void capture (Knight k) {
        System.out.println("TOO SLOW BUDDY");
    }
}

这是我对两次调用时会发生什么的理解:

调用1:p1.capture(p2)

从p1调用捕获方法。通过动态类型查找,它看到p1的动态类型是 Knight 。所以它看起来在Knight子类中。 p2作为参数传入。要查看在Knight子类中调用哪个捕获方法,它会检查p2的静态类型,即 piece 。因此,印有“骑士无聊”。这是正确的输出,但我的推理是正确的吗?

致电2:p2.capture(p1)

使用相同的推理,从p2调用捕获方法。通过动态类型查找,它看到p2的动态类型是 Knight 。所以它看起来在Knight子类中。 p1作为参数传入。要查看要调用的捕获方法,它会查看p1的静态类型,即 Knight 。因此,打印出“TOO SLOW BUDDY”。显然,我的推理是错误的,因为那不是真正印刷的。任何方向?

谢谢!

6 个答案:

答案 0 :(得分:5)

在第二次调用中,您只能调用Piece类的方法或其子类中的相同方法。这就是为什么它会调用捕获(Piece p)而不是捕获(Knight k)。后者特定于骑士类。

例如,当我们有“List a = new Arraylist();”时,你只能调用在List中声明的方法,而不能在ArrayList中调用类似的方法。

答案 1 :(得分:2)

当您向@Override方法添加Knight注释时,它变得清晰。

public void capture (Knight k) {
    System.out.println("TOO SLOW BUDDY");
}

此方法未被覆盖 - 它是新的,已在Knight类中添加。

因此它只能用于Knight类型的对象 - 例如:Knight k = new Knight();

你没有这样的例子,在Knight上以Knight作为参数调用此方法。你在Knight with Piece上调用capture,在with Piece上调用

    p1.capture(p2); // call 1; "Knight is bored" is supposed to be printed
    p2.capture(p1); // call 2; "knight is bored" is supposed to be printed
    p1.capture(p1); // call 3:  TOO SLOW BUDDY <- look here :)

答案 2 :(得分:2)

 p2.capture(p1); // call 2; "knight is bored" is supposed to be printed

这里你在Piece类对象上调用capture方法,因为你已经传递了p1(Knight)类引用,它将调用类Knight的重写捕获方法。

 public void capture (Piece p) {
        System.out.println("Knight is bored");
    }

答案 3 :(得分:1)

如果您运行以下代码 -

public class Piece {

public static void main (String[] args) {
    Piece p2 = new Knight();
    Knight p1 = new Knight();
    p1.capture(p2); 
    p2.capture(p1); 
}

public void capture () {
    System.out.println("Capturing");
}

public void capture (Piece p) {
    System.out.println("I'm bored");
}

}

  class Knight extends Piece {


  //    public void capture (Piece p) {
  //        System.out.println("Knight is bored");
  //    }

public void capture (Knight k) {
    System.out.println("TOO SLOW BUDDY"+k);
}

}

结果是 -

我很无聊

我很无聊

因此,动态查找检查子类是否已覆盖该函数。

答案 4 :(得分:0)

我记得,我已经学会了“扩展”意味着“将旧版本放在旧版本上但不删除它”,如果你“覆盖”该方法,就会像你描述的那样。 在你的情况下,如果你调用“p1.capture(p1)”,它应该导致“太慢了”(但我没试过)。

答案 5 :(得分:0)

我不认为这个样本告诉你静态和放大之间的差别。动态类型。你甚至不需要考虑超类和子类。它只是告诉你方法定义。 ---&GT;只有当调用者,方法名称,参数名称和参数的类型都相同时,才会调用正确的方法。