为什么子类的私有变量在存储在超类类型变量中时会保留?

时间:2012-11-25 19:45:11

标签: java inheritance subclass superclass

我一定错过了继承中的基本内容,因为它对我没有意义。

鉴于这两个类:

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变量,因此它是合法的 - 但是当你这样做时,degree中不存在p

这就是我认为原因在于相反的事实是违法的 (Student s = new Person("John");) - 因为s不会将其他变量(degree)初始化。

2 个答案:

答案 0 :(得分:3)

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

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!

你会得到一个ClassCastException,因为在程序的那一点上,p现在是一个对象(Teacher的一个实例)的引用,它不是{{1} }}

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

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

答案 1 :(得分:0)

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

相关问题