【问题标题】:Output in case of chaining inheritance链式继承时的输出
【发布时间】:2016-01-25 17:55:29
【问题描述】:
class Monster {
    boolean frighten(int x) {
        System.out.println("Monster");
        return true;
    }
}

class Vampire extends Monster {
    boolean frighten(byte x) {
        System.out.println("Vampire");
        return true;
    }
}

class Dragon extends Monster {
    boolean frighten(int x) {
        System.out.println("Dragon");
        return true;
    }
}


class Sample {
    public static void main(String s[]) {
        Monster[] inst = new Monster[3];
        inst[0] = new Monster();
        inst[1] = new Vampire();
        inst[2] = new Dragon();

        for (int i = 0; i < 3; i++) {
            inst[i].frighten(i);
        }
    }
}

当我在MonsterDragon 类中使用x 作为int 运行上述代码时,代码可以按我预期的方式正常运行。但是,当我通过在 MonsterDragon 类中将 x 的类型从 int 更改为 long 来运行代码时,它会打印以下内容:

Monster                           
Monster                                 
Monster                                   

有人能解释一下输出背后的逻辑吗?

【问题讨论】:

  • Vampire 不会覆盖frighten(int),它定义了一个重载。在Monster 类中将其更改为longDragon 也不会覆盖该方法。这就是为什么你应该注释方法@Override 如果你希望该方法被覆盖。
  • 我什至不会称之为继承。您错误地使用了 extends 关键字。详细地说,Monster 应该是不同类型怪物的模具或蓝图。这没有实现。

标签: java inheritance casting


【解决方案1】:

您没有将byte 传递给您的Vampire 实例;您正在通过循环传递int。因为Monster 接受int,所以它就是被调用的对象。

实际上,您是在重载您的方法,而不是覆盖它 - 您有一个具有相同名称和两个相同签名的方法。

在重写方法时确实应该使用同构类型,这样就不会遇到这样的问题。有效:将Vampirefrighten 的签名更改为接受int 而不是byte

使用 @Override 注释您的方法将让编译器帮助选择类似的内容。

// Would cause a compilation error since the method isn't overridden
@Override
public boolean frighten(byte x) {
    return true;
}

【讨论】:

  • 问题不在于吸血鬼类。如果 Monster 或 drangon 类中 x 的类型是 int,那么它可以正常工作并打印以下内容:Monster Monster Dragon
  • @Nain:我不会称其为“工作正常”,因为代码的意图是调用 frighten 某个类的 Monster。这是我可以看到的最明显的问题,因为您重载了方法而不是覆盖了它,所以您没有看到“吸血鬼”。
【解决方案2】:

如果您的意图是覆盖,您可以使用注释。然后编译器将帮助您发现此类错误。例如编译器会看到这里有一个错误。

 class Vampire extends Monster
    {
      @Override 
      boolean frighten(byte x)
      {
       System.out.println("Vampire");
       return true;
      }
     }

【讨论】:

  • 将注释向下移动一层。你不能在课堂上使用它。
【解决方案3】:

当你写作时

inst[i].frighten(i);

因为inst[i]Monster 类型,编译器必须在Monster 类上找到与参数匹配的frighten 方法——在您的实际代码中,它是frighten(int)

它在您传递给它的所有 Monster 实例上调用此方法 - 在运行时类是什么并不重要,该方法是在编译时选择的。

这意味着Vampire.frighten(byte) 方法永远不会被调用——它是一个重载,而不是一个覆盖,因为签名frighten(int) 和@987654330 @不匹配。

如果将Monster 上的frighten 方法的参数更改为long,编译器只能从Monster 上定义的方法中进行选择,因此它知道它可以安全地在所有实例上调用的唯一方法是frighten(long):两个子类都没有覆盖这个方法——所以行为是基类的行为。

如果将Dragon 上的frighten 方法的参数更改为long,则它不再覆盖基类中的方法——因此行为是基类的行为。

阻止这种“意外”行为的方法是始终将@Override 添加到您认为覆盖基类中的方法的方法中。如果带有该注解的方法实际上没有覆盖基类上的方法,编译器会报错。

【讨论】:

    猜你喜欢
    • 2016-03-05
    • 1970-01-01
    • 2017-08-14
    • 2015-03-11
    • 2012-10-13
    • 2021-10-18
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    相关资源
    最近更新 更多