为什么子类在upcast时会响应?

Why does the sublcass respond when upcasted?

interface Readable {
    public void printTitle();
}

class WebText implements Readable {
    public String title;

    public void printTitle(){
        System.out.println("This Webpage title is "+ title);
    }

    public void setTitle(String title){
        this.title = title;
    }
}

class Blog extends WebText {

    public void printTitle(){
        System.out.println("The Blog title is " + title);
    }
}

class ReadingTester{
    public static void main(String [] arg) {
        Blog b1 = new Blog();
        WebText b2 = new Blog();

        b1.setTitle("How to upcast");
        b2.setTitle("Dangers of upcasting");

        b1.printTitle();
        b2.printTitle();

    }
}

上面的代码是我正在做的家庭作业,但我真的不确定发生了什么。当我 运行 代码时,它输出:

博客标题是:如何向上转换

博客标题是:向上转型的危险

我很困惑的是为什么第二个打印出 "The Blog title is" 而不是 "This Webpage title is:"。由于 b2 被升级为 WebText,class 不应该是响应的那个吗?我在网上找到的所有内容都表明向上转换是安全的,但这是不是一个例子?我真的很困惑,非常感谢您的帮助,非常感谢!

Blog 中的 printTitle 覆盖 WebText 中的 printTitle。由于 b2 在运行时实际上是 Blog 的实例,调用 printTitle 将调用 Blog 中的实例,即使在编译时 b2 是类型WebText。这是一种多态.

这种行为实际上是可取的,因为它允许您拥有一个 WebText 类型的变量,该变量能够存储许多不同类型的网络文本,包括博客、新闻文章和堆栈溢出答案.这些类型中的每一种都可以选择以不同方式打印它们的标题。 This post might help you understand why we do this better.

Why is this said to be safe then?

这是安全的,因为它不会抛出异常。这是不安全的,因为 b2.printTitle 中的 s 可能不会调用 WebText 中的方法,但无论如何你不应该首先假设,除非方法是 final.

在编译时,WebText b2 = new Blog();检查是否可以完成对b2 的方法调用。它看到 Blog 有 setTitleprintTitle。所以它将 b2 视为博客。

如果您在博客中有不同的方法,比方说,printTwice(),并且您尝试调用 b2.printTwice(),编译器会抛出编译时错误,因为它无法将 WebText 对象视为Blog 对象(因为 b2 不能引用 Blog 对象)