简体   繁体   English

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

[英]Why are subclasses' private variables kept when stored in a superclass type variable?

I must have missed something basic in inheritance since it doesn't make sense to me. 我一定错过了继承中的一些基本知识,因为这对我来说没有意义。

Given these two classes: 给定这两个类:

class Person
{
   private String name;
}

class Student extends Person
{
   private String degree;
}

Why is it possible to create a new Student object, store it in a Person type variable and still be able to keep the variable String degree and have access to it? 为什么可以创建一个新的Student对象,将其存储在Person类型的变量中,并且仍然能够保留变量String degree并可以访问它?

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

I thought that this is possible to use the above initialization because p will not have any variable other than name , since a Person variable can't contain a degree variable, and so it's legal - but when you do that, degree doesn't exist in p . 我认为可以使用上述初始化,因为p除了name之外将没有任何变量,因为Person变量不能包含degree变量,所以这是合法的-但是当您这样做时, degree不存在在p

That's what I thought the reason was behind the fact that the opposite is illegal 这就是我认为相反的事实是非法的事实的原因
( Student s = new Person("John"); ) - because then s will not have its other variable ( degree ) initialized. Student s = new Person("John"); )-因为s不会初始化其其他变量( degree )。

A variable with a type of reference to a supertype can hold a reference to an instance of a subtype. 具有对超类型的引用类型的变量可以保存对子类型的实例的引用。 Assigning the subtype instance to the variable does not change the instance in any way; 分配亚型实例变量以任何方式改变的情况下; it just broadens the type of reference. 它只是扩大了参考的类型。 All the instance data is still there, and can be retrieved by a down-cast. 所有实例数据仍然存在,并且可以通过向下广播检索。 That is, 那是,

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

is exactly the same as: 与以下内容完全相同:

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

EDIT Perhaps this will help clarify things. 编辑也许这将有助于澄清事情。 Suppose there was a second subclass of Person : 假设存在Person的第二个子类:

class Teacher extends Person
{
    private String department;
}

Now you can do this: 现在您可以执行以下操作:

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

But if you later tried to do this: 但是,如果您以后尝试执行此操作:

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

you'll get a ClassCastException because at that point in the program, p is now a reference to an object (an instance of Teacher ) that is not a Student . 您将获得ClassCastException因为在程序中的那一点, p现在是对不是Student的对象( Teacher的实例)的引用。

Here's an analogy. 这是一个比喻。 In English, you might say, "I have a pet animal". 用英语,您可能会说:“我有一只宠物”。 This says nothing about the type of animal. 这与动物的种类无关。 (You cannot know whether the pet barks, for instance.) On the other hand, if you say, "I have a pet dog", then it makes sense to ask whether it barks at strangers. (例如,您不知道宠物是否吠叫。)另一方面,如果您说“我有一只宠物狗”,那么问它是否对陌生人吠叫是很有意义的。 The key point is: calling your pet an animal doesn't change the fact that it is (or is not) a dog . 关键是: 将宠物称为动物不会改变它是(或不是)狗的事实 Exactly the same thing is going on with Java references—using a more general (eg, base class) reference type to store the object reference does not change the nature of the object itself. Java引用确实发生了同样的事情-使用更通用的(例如,基类)引用类型来存储对象引用不会改变对象本身的性质。 You lose knowledge of the details of the object, but those details are still there. 您会丢失对象详细信息的知识 ,但是这些细节仍然存在。

To repeat the point I made in my comment: you never assign objects to variables in Java; 重复我在评论中提出的观点:在Java中,永远不要将对象分配给变量; you only assign references to objects. 您只分配对对象的引用 Or, to put it another way, none of your variables are objects. 或者,换句话说,您的变量都不是对象。

Variables don't hold objects. 变量不持有对象。 Variables hold references , which identify objects. 变量包含引用 ,这些引用 标识对象。 If one has a list of automotive vehicle identification numbers (VIN in the US), the list itself may contain numbers for cars of many different sorts; 如果列出了汽车识别号(在美国为VIN),则列表本身可能包含许多不同类型的汽车的号。 from the perspective of the list, each number is known to identify a Vehicle, but one number might identify FordFocus, another a ToyotaPrius, another a ChevroletSebringConvertible, etc. If one writes the number of a ChevroletSebringConvertible on the list, the list would have no idea that it was a convertible, and so one couldn't say "Raise the top on the fifth car on the list" without first establishing that the car identified by the fifth VIN had a convertible top. 从列表的角度来看,已知每个数字都可以标识车辆,但是一个数字可以标识FordFocus,另一个可以标识ToyotaPrius,另一个可以标识ChevroletSebringConvertible,等等。如果在该列表上写了一个ChevroletSebringConvertible的数字,则该列表将没有认为这是敞篷车,因此如果不先确定第五个VIN所标识的汽车具有敞篷车顶,就不能说“提高列表中第五辆车的顶部”。 The top wouldn't be something that came into existence when the car was identified as a convertible; 当汽车被确认为敞篷车时,顶部就不会存在。 the top and its state (raised or lowered) would continue to exist regardless of who knew about them. 无论谁知道它们,顶部及其状态(升高或降低)都将继续存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM