3

所以我在理解这个在课堂上展示的例子时遇到了一些麻烦——它应该说明 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。因此,打印了“Knight is Bored”。这是正确的输出,但我的推理是否正确?

调用 2:p2.capture(p1)

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

谢谢!

4

6 回答 6

5

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

例如,当我们有“List a = new Arraylist();”时,您只能调用在 List 中声明的方法,而不是在 ArrayList 中附加但外观相似的方法。

于 2012-06-28T05:28:22.023 回答
2

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

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

这个方法没有被覆盖 -它是新的,在Knight类中添加。

所以它只能用于具有类型的对象Knight- 例如:Knight k = new Knight();

你没有这样的例子,这个方法被Knight作为Knight参数调用。你调用capture了 Knight with Piece 和 Piece with 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
    p1.capture(p1); // call 3:  TOO SLOW BUDDY <- look here :)
于 2012-06-28T05:30:00.337 回答
2
 p2.capture(p1); // call 2; "knight is bored" is supposed to be printed

在这里,您正在调用 Piece 类对象的捕获方法,并且由于您已通过 p1(Knight) 类引用,它将调用 Knight 类的覆盖捕获方法。那是

 public void capture (Piece p) {
        System.out.println("Knight is bored");
    }
于 2012-06-28T05:34:13.807 回答
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);
}

}

结果是——

我很无聊

我很无聊

所以动态查找检查子类是否覆盖了函数。

于 2012-06-28T05:37:27.450 回答
0

我记得,我了解到“扩展”的意思是“将新的放在旧的上面但不删除它”,如果你“覆盖”该方法,它会像你描述的那样。在您的情况下,如果您调用“p1.capture(p1)”,它应该会导致“TOO SLOW BUDDY”(但我没有尝试过)。

于 2012-06-28T05:27:02.903 回答
0

我不认为这个示例告诉你 static 和 dynamic type 之间的区别。你甚至不需要考虑超类和子类。它只是告诉你方法定义。---> 只有当调用者、方法名、参数名和参数类型都相同时,才会调用正确的方法。

于 2012-06-28T05:27:45.307 回答