为什么在调用子类的特定方法时必须转换对象?
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
语句设置为 Adult
或 Child
。)可能是特定情况下,它保证变量将引用特定的 class,但 Java 语言不会特殊处理这些情况。如果变量声明为 Person
类型,则只能对其调用 Person
方法。
如果你写Adult z = new Adult()
,那么你可以调用z.drive()
,因为变量保证只引用成人,不会引用儿童。
所以,例如,
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 anAdult
instance?
您正在创建一个 Adult
对象,但是声明 Person z
表示允许变量 z
引用 any样的人,不仅仅是成年人。您可以在下一行写 z = new Child()
。
当您在 z
上调用方法时,Java 会检查它对变量 可以 引用的所有对象是否有效。它不会分析前面的代码来尝试找出它实际 引用的具体类型,因为在大多数情况下这是不可能的。 (例如,变量可以作为方法参数传入,或者可以根据 if
语句设置为 Adult
或 Child
。)可能是特定情况下,它保证变量将引用特定的 class,但 Java 语言不会特殊处理这些情况。如果变量声明为 Person
类型,则只能对其调用 Person
方法。
如果你写Adult z = new Adult()
,那么你可以调用z.drive()
,因为变量保证只引用成人,不会引用儿童。