为什么在调用子类的特定方法时必须转换对象?

Why do you have to cast objects when calling particular methods of a subclass?

所以,例如,

Person p = New Person()

Person z = New Adult()

假设成人 Class 有自己的方法 drive(),为什么我不能这样做:

z.drive()

我知道这行不通,但这行不通背后的逻辑是什么?当您说:Person z = New Adult() 时,您不是指定它是一个 Adult 实例吗?

它背后的 "logic" 不起作用是因为 Java 就是这样设计的。 Java 是一种 静态类型 语言,这意味着每个变量在编译时都有一个声明的类型。 Java 也是 强类型 这意味着可以保存的值和支持的操作仅限于声明的类型。此强制执行称为 type safety.

static type checking 的优点是编译器会阻止您分配不兼容的类型或调用不可用的方法。可以在编译时和运行时捕获错误。

尝试搜索 "strong vs. weak typing",它将提供更多详细信息、论点和方法的 pros/cons。

你问这个,我引用:

When you say: Person z = New Adult(), aren't you specifying it is an Adult instance?

不,恰恰相反,更准确地说:

//Main.java, first version.
class Person { 
    public void drive() {
        System.out.println("Person.drive");
    }
}

class Adult extends Person {

    @Override 
    public void drive() {
        System.out.println("Adult.drive");
    }
}

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        p.drive();  // Person.drive

        Person a = new Adult();
        a.drive();  // Adult.drive
    }
}

第二个变体,这次 Person 没有 drive() 方法:

//Main.java, second version.
class Person {}

class Adult extends Person {

    // NO overriding here ..
    public void drive() {
        System.out.println("Adult.drive");
    }
}

public class Main {
    public static void main(String[] args) {
        Person p = new Adult(); // 1

        // Now this cast is needed:
        Adult  a = (Adult) p;   // 2

        a.drive();  // Adult.drive(), as before  // 3
    }
}

将这两个单独的程序放在一个Main.java中,分别编译和运行。

让我们考虑第二个版本。请看标有 //1 和 //2 的行。 在 //1 中发生的是所谓的 class Adult 切片。 Adult 是 Person 的扩展,因此有权要求比 Person 对象更多的内存。但是你将一个 Person 分配给一个 Adult 对象,所以并不是更大的 Adult 对象的所有内存 可能 都被初始化。

因此,Jave 敦促您将 Person 转换为 //2 中的 真实 成人对象,以便您向它表明您 知道 你在做什么。只有 然后 才允许在 //3.

中调用 a.drive()

希望这有助于澄清一些事情。

此致,米查

When you say: Person z = New Adult(), aren't you specifying it is an Adult instance?

您正在创建一个 Adult 对象,但是声明 Person z 表示允许变量 z 引用 any样的人,不仅仅是成年人。您可以在下一行写 z = new Child()

当您在 z 上调用方法时,Java 会检查它对变量 可以 引用的所有对象是否有效。它不会分析前面的代码来尝试找出它实际 引用的具体类型,因为在大多数情况下这是不可能的。 (例如,变量可以作为方法参数传入,或者可以根据 if 语句设置为 AdultChild。)可能是特定情况下,它保证变量将引用特定的 class,但 Java 语言不会特殊处理这些情况。如果变量声明为 Person 类型,则只能对其调用 Person 方法。

如果你写Adult z = new Adult(),那么你可以调用z.drive(),因为变量保证只引用成人,不会引用儿童。