所以,例如,
Person p = New Person()
Person z = New Adult()
假设Adult Class有自己的方法叫做drive(),为什么我不能这样做:
z.drive()
我知道这不起作用,但这背后的逻辑是什么?当您说:Person z = New Adult()
时,您是不是指定它是Adult
实例?
答案 0 :(得分:2)
"逻辑"它背后不起作用是因为Java的设计工作方式。 Java是一种静态类型的语言,这意味着每个变量在编译时都具有声明的类型。 Java也是强类型,这意味着可以保留的值和支持的操作仅限于声明的类型。此强制执行称为type safety。
static type checking的优点是编译器会阻止您分配不兼容的类型或调用不可用的方法。可以在编译时和运行时捕获错误。
尝试搜索"强与弱打字"这将提供更多细节,论点和方法的优点/缺点。
答案 1 :(得分:0)
你问这个,我引用:
当你说:Person z = New Adult()时,你不指定它是一个 成人实例?
不,恰恰相反,更确切地说:
//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
}
}
Second Variation,这次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中发生的事情是所谓的成人类切片。 Adult是Person的扩展,因此有权声明比Person对象更多的内存。但是,您将Person分配给Adult对象,因此不会对较大的Adult对象的所有内存进行初始化。
因此,Jave敦促您将人员转移到// 2中的真实成人对象,以便向您展示您知道您正在做什么。只允许然后在// 3中调用a.drive()。
希望,这有助于澄清一些事情。
问候,Micha
答案 2 :(得分:0)
当您说:
Person z = New Adult()
时,您是不是指定它是Adult
个实例?
您正在创建Adult
对象,但声明Person z
表示允许变量z
引用任何类型的人,而不是只是一个成年人。你可以在下一行写下z = new Child()
。
当您在z
上调用方法时,Java会检查它对于可以引用的变量的所有对象是否有效。它不会分析前面的代码来试图找出它实际上 所引用的特定类型,因为在大多数情况下这是不可能的。 (例如,变量可以作为方法参数传入,或者可以根据Adult
语句设置为Child
或if
。)可能是保证变量将引用特定类的特定情况,但Java语言不会特别处理这些情况。如果变量是使用Person
类型声明的,则只能在其上调用Person
方法。
如果你写Adult z = new Adult()
,那么你可以拨打z.drive()
,因为该变量只能保证成人,而不是孩子。