0

我一定错过了一些基本的继承,因为它对我来说没有意义。

鉴于这两个类:

class Person
{
   private String name;
}

class Student extends Person
{
   private String degree;
}

为什么可以创建一个新Student对象,将其存储在Person类型变量中,并且仍然能够保留该变量String degree并可以访问它?

Person p = new Student("John", "Master's");

我认为可以使用上述初始化,因为p除了 之外没有任何变量name,因为Person变量不能包含degree变量,所以它是合法的 - 但是当你这样做时degreep.

这就是我认为的原因是相反的事实是非法的
Student s = new Person("John");) - 因为那样s不会degree初始化它的另一个变量()。

4

2 回答 2

3

具有对超类型的引用类型的变量可以保存对子类型实例的引用。将子类型实例分配给变量不会任何方式改变实例;它只是扩大了参考的类型。所有实例数据仍然存在,并且可以通过向下转换来检索。那是,

Student s = new Student("John", "Master's");
Person p = s; // no cast needed for a widening conversion

与以下内容完全相同:

Person p = new Student("John", "Master's");
Student s = (Student) p; // cast required for a narrowing conversion

编辑也许这将有助于澄清事情。假设有第二个子类Person

class Teacher extends Person
{
    private String department;
}

现在你可以这样做:

Person p = new Teacher("Fred", "Physics");
Teacher t = (Teacher) p;

但是,如果您后来尝试这样做:

p = new Teacher("Fred", "Physics");
Student s = (Student) p; // Error!

你会得到 aClassCastException因为在程序中,p现在是对Teacher不是 a 的对象(的实例)的引用Student

这是一个类比。用英语,你可能会说,“我有一只宠物”。这并没有说明动物的类型。(例如,您无法知道宠物是否吠叫。)另一方面,如果您说“我有一只宠物狗”,那么询问它是否对陌生人吠叫是有意义的。关键点是:称你的宠物为动物并不会改变它是(或不是)狗的事实。Java 引用的情况完全相同——使用更通用的(例如,基类)引用类型来存储对象引用不会改变对象本身的性质。你失去了对物体细节的了解,但那些细节仍然存在。

重复我在评论中提出的观点:您永远不会将对象分配给 Java 中的变量;您只分配对对象的引用。或者,换句话说,你的变量都不是对象。

于 2012-11-25T19:48:32.917 回答
0

变量不包含对象。变量持有引用,它标识对象。如果一个人有一个汽车识别号码列表(美国的 VIN),这个列表本身可能包含许多不同类型的汽车的号码;从列表的角度来看,每个数字都可以识别车辆,但一个数字可能会识别 FordFocus、另一个 Toyota Prius、另一个 ChevroletSebringConvertible 等。如果将 ChevroletSebringConvertible 的数字写在列表上,则该列表将没有认为它是敞篷车,因此如果没有首先确定由第五个 VIN 识别的汽车具有敞篷车顶,就不能说“举起列表中第五辆汽车的顶篷”。当汽车被确定为敞篷车时,顶篷就不会出现。顶部及其状态(升高或降低)将继续存在,无论谁知道它们。

于 2013-12-09T17:56:01.080 回答