【问题标题】:Java -- static & dynamic type -- "what does this print?"Java——静态和动态类型——“这打印什么?”
【发布时间】:2012-06-29 14:34:17
【问题描述】:

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

调用 2:p2.capture(p1)

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

谢谢!

【问题讨论】:

    标签: java oop inheritance dynamic static


    【解决方案1】:

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

    【讨论】:

    • 是的,p1.capture(p1) 导致“太慢的伙伴”;但是,我对其他两种情况感到困惑,而不是这种情况;)
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 嗯。那么因为p2的静态类型是Piece,所以它只知道capture(Piece p)方法,不知道capture(Knight k)方法?那么,它如何能够进入 Knight 子类并采用该版本的方法?抱歉,还是有点糊涂。
      • 这是因为 Knight 扩展了 Piece 而 p2 是 Knight 对象。这意味着您只能调用 Piece 方法,但如果 Knight 有一个具有相同签名的方法,它将改为调用那个方法。
      • 你的意思是 p2 是 Piece 类型的对象吗?
      • @RyanYu:是的,就像我的示例中的a 是其余代码中的List。但是当在a 上调用方法时,它被认为是ArrayList
      • @RyanYu:我认为 p2 是 Piece 类型的引用和 Knight 类型的对象..希望它能回答你......
      【解决方案4】:

      当您将@Override 注释添加到Knights 方法时,它会变得清晰。

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

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

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

      您没有这样的示例,即在 Knight 上以 Knight 作为参数调用此方法。你在 Knight with Piece 和 Piece with knight 上调用了capture

          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 :)
      

      【讨论】:

      • 好的,谢谢。当你说“它只能用于 Knight 类型的对象”时,你指的是它们的静态类型,对吗?换句话说,奈特 n;应该是骑士类型。
      • @Ryan Yu,你有两件事——引用类型和动态对象对象:Type staticTypeOfReference = new DynamicPolimorficObjectThatCanExtendTypeDeclared(); :)
      • 好的,让我看看我是否有这个权利,最后:对于 p1.capture(p2),它看到 p1 是 Knight 类型,而 p2 是 Piece 类型,所以它检查 Knight 子类对于将 Piece 作为参数的捕获方法。它找到了这个,并打印出“Knight is bored”
      • 此外,对于 p2.capture(p1),它看到 p2 的类型是 Piece,而 p1 的大小是 Knight。它在类中查找正在从 (p2 -- Piece) 调用捕获,并发现没有接受 Knight 类型参数的方法。但是有一种方法可以接受 Piece 类型的参数!然后,动态查找告诉该方法在子类 (Knight) 中检查覆盖它找到的此捕获方法的方法。然后它使用这种覆盖方法来打印“骑士很无聊”。
      • @Ryan Yu - Furthermore, for p2.capture(p1), it sees p2 is of type Piece - 这里的 p2 类型无关紧要,它被动态解析为 Knight,当您将 obiect 传递给某个方法时会发生静态解析 - 然后正在检查静态类型,并且对其子类的实际引用根本不重要。 p2.capcure(p1) - 此调用知道 p2 是 Knight 类的对象,其引用类型为 Piece(但在这里无关紧要......)并且它知道 p1 的引用类型为调用构造函数)Knight,它是 Piece 的子类。
      【解决方案5】:
       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");
          }
      

      【讨论】:

        【解决方案6】:

        如果你运行以下代码 -

        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);
        }
        

        }

        结果是——

        我很无聊

        我很无聊

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

        【讨论】:

          猜你喜欢
          • 2016-09-26
          • 2014-09-27
          • 1970-01-01
          • 1970-01-01
          • 2012-07-11
          • 1970-01-01
          • 2013-12-28
          相关资源
          最近更新 更多