java 为什么不能引用子类对象引用父类对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2145767/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 19:40:35  来源:igfitidea点击:

Why can't reference to child Class object refer to the parent Class object?

c#java.netc++

提问by claws

I was explaining OOP to my friend. I was unable to answer this question. (How shameful of me? :( )

我正在向我的朋友解释 OOP。我无法回答这个问题。(我有多丢人?:()

I just escaped by saying, since OOP depicts the real world. In real world, Parent's can accommodate children but children cannot accommodate parents. same is the case in OOP.I know its stupid. :P

我只是说,因为 OOP 描绘了现实世界。在现实世界中,父母可以容纳孩子,但孩子不能容纳父母。在 OOP 中也是如此。我知道它很愚蠢。:P

class Parent
{
  int prop1;
  int prop2;
}

class Child : Parent // class Child extends Parent  (in case of Java Lang.)
{
  int prop3;
  int prop4;

  public static void Main()
  {
     Child aChild = new Child();
     Parent aParent = new Parent();
     aParent = aChild;// is perfectly valid.
     aChild = aParent;// is not valid. Why??

  }
}

Why isn't this statement valid?

为什么这个声明无效?

 aChild = aParent;// is not valid. Why??

since aChild's members are superset of aParent's members. Then why can't aChild accommodate a parent.

因为aChild 的成员是aParent 成员的超集。那为什么aChild不能容纳父母。

回答by Kornel Kisielewicz

Exactly because aChild is a superset of aParent's abilities. You can write:

正是因为 aChild 是 aParent 能力的超集。你可以写:

class Fox : Animal

Because each Fox is an Animal. But the other way is not always true (not every Animal is a Fox).

因为每只狐狸都是动物。但另一种方式并不总是正确的(并非每个动物都是狐狸)。

Also it seems that you have your OOP mixed up. This is not a Parent-Child relationship, because there's no composition/trees involved. This is a Ancestor/Descendant inheritance relation.

此外,您似乎混淆了您的 OOP。这不是父子关系,因为不涉及组合/树。这是祖先/后代继承关系。

Inheritance is "type of" not "contains". Hence it's Fox is a type of Animal, in your case it doesn't sound right -- "Child is a type of Parent" ? The naming of classes was the source of confusion ;).

继承是“类型”而不是“包含”。因此它的Fox 是一种 Animal,在你的情况下它听起来不对 - “Child is a type of Parent”?类的命名是混淆的根源;)。

class Animal {}
class Fox : Animal {}
class Fish : Animal {}

Animal a = new Fox(); // ok!
Animal b = new Fish(); // ok!
Fox f = b; // obviously no!

回答by Thomas L?tzer

If it was valid, what would you expect when you read aChild.prop3? It is not defined on aParent.

如果它是有效的,当你阅读时你会期待什么aChild.prop3?它没有在 上定义aParent

回答by Pranavan Maru

class "Child" extends "Parent"

“子级”扩展了“父级”

"child class object is inherently a parent class object"

“子类对象本质上是父类对象”

 Child aChild = new Child();
 Parent aParent = new Parent();
 aParent = aChild;// is perfectly valid.
 aChild = aParent;// is not valid.

in a code segment like a normal assignment operation, the above is read from right to left. line 3 of the code segment reads - "aChild (a Child class object) is a Parent" (due to inheritence child class objects become superclass objects inherently) thus line no.3 is valid.

在像普通赋值操作一样的代码段中,上面的内容是从右到左读取的。代码段的第 3 行读取 - “aChild(子类对象)是父类”(由于继承子类对象本质上成为超类对象)因此第 3 行是有效的。

whereas in line no.4 it reads, "aParent (a Parent class object) is a child" (inheritence doesn't say that superclass objects will become child class objects. it says the opposite) thus line no.4 is invalid.

而在第 4 行中,“aParent(父类对象)是子类”(继承并没有说超类对象将成为子类对象。它说的是相反的)因此第 4 行是无效的。

回答by Adamski

I would say your example is flawed in that Childextends from Parent, which doesn't really follow the "is-a" relationship particularly well. Far better to have a relationship whereby both Childand Parentinherit from a single base class: Person.

我会说你的例子有缺陷,ChildParent,它并没有真正很好地遵循“is-a”关系。最好有一种关系,即ChildParent都继承自一个基类:Person.

Using that approach it would be easier to explain to your friend why:

使用这种方法可以更容易地向您的朋友解释原因:

Person p = new Child();

... is valid, but the following is not:

... 是有效的,但以下不是:

// We do *not know* that the person being referenced is a Child.
Child c = person;

It is precisely this reason why this assignment is disallowed in Java: What would the additional child fields be initialised with in this case?

正是这个原因在 Java 中不允许这种分配:在这种情况下,附加的子字段将用什么初始化?

回答by Rajesh Nair

If I have a class, say

如果我有课,说

class A{
    getA(){

    }
}

class B extend A{
    getB(){

    }
}

Now class Bknows two methods getA()and getB(). but class Aknows only getA()method.

现在class B知道两种方法getA()getB()。但class A只知道getA()方法。

So, if we have class B obj = new class A();we have made a mess , as it is valid for class Bto reference methods getA()and getB()but only getA()is valid. That explains the issue.

所以,如果我们有class B obj = new class A();我们弄得一团糟,因为它对class B引用方法有效getA()getB()但仅getA()有效。这就解释了这个问题。

This is my understanding of not allowing child class hold reference of parent class.

这是我对不允许子类持有父类引用的理解。

回答by Anuj Sharma

The Heap-Stack answer by AaronLSmakes perfect technical sense.

AaronLS的堆堆栈答案具有完美的技术意义。

References are store on stack while objects are store on heap. We can assign child object to parent type reference because child is type of parent and child object has reference for parent class. While parent is not of type child. Parent object doesn't have reference to child so child reference can't point to parent object.

引用存储在堆栈上,而对象存储在堆上。我们可以将子对象分配给父类型引用,因为子对象是父类的类型,子对象具有父类的引用。而父母不是孩子类型。父对象没有对子对象的引用,因此子引用不能指向父对象。

This is the reason why we can cast decimal to int and int to decimal. But we can not cast parent-child both ways. Because parent has no clue about its children's references.

这就是为什么我们可以将decimal转换为int和int转换为decimal的原因。但是我们不能双向施展父子关系。因为父级对其子级的引用一无所知。

Int i = 5;
Decimal d = 5.5;

d = i;

or 

i = d;

Both are valid. But same is not the case with reference types which are stored on heap.

两者都有效。但存储在堆上的引用类型的情况并非如此。

回答by Sergey Teplyakov

Semantically, inheritance denotes an “is a” relationship. For example, a bear “is a” kind of mammal, a house “is a” kind of tangible asset, and a quick sort “is a” particular kind of sorting algorithm. Inheritance thus implies a generalization/ specialization hierarchy, wherein a subclass specializes the more general structure or behavior of its superclasses. Indeed, this is the litmus test for inheritance: If B is not a kind of A, then B should not inherit from A. In your case it means, that Parent "is a" child, but not vice versa.

从语义上讲,继承表示“是一个”关系。例如,熊“是”一种哺乳动物,房子“是”一种有形资产,而快速排序“是”一种特定的排序算法。因此,继承意味着泛化/特化层次结构,其中子类专门化其超类的更一般的结构或行为。事实上,这是继承的试金石:如果 B 不是 A 的一种,那么 B 不应该从 A 继承。在您的情况下,这意味着 Parent “是”孩子,但反之则不然。

P.S. I think in this case you violates main inheritance principles.

PS 我认为在这种情况下你违反了主要的继承原则。

回答by Andreas Dolk

I think, you chose a wrong model for real-life Parents and Children ;) In real life, a Parent is always a Child and a Child can be a Parent.

我认为,您为现实生活中的父母和孩子选择了错误的模型;) 在现实生活中,父母永远是孩子,孩子可以是父母。

If you turn it around, it works:

如果你把它转过来,它会起作用:

class Child {
  Child[] parents;
}

class Parent : Child {
  Child[] children;
}

A parent is-achild (of his/her own parents) and we can express:

父母(他/她自己父母的)孩子,我们可以表达:

Child aChild = aParent;

because every parent is a child as well, but not

因为每个父母也是孩子,但不是

Parent aParent = aChild;

because not all children are parents.

因为并不是所有的孩子都是父母。

回答by Janusz

If you take a parent class and extend it the class has all the features the parent class has plus some more.

如果您采用父类并对其进行扩展,则该类具有父类的所有功能以及更多功能。

If you assign an object of the type child to an object of the type parent like:

如果将 child 类型的对象分配给 parent 类型的对象,例如:

Parent aParent = aChild;

you reduce the interface of the child object to the features of the base class. This is perfectly ok because it means that some new features of the child aren't used in that context.

您将子对象的接口减少到基类的功能。这完全没问题,因为这意味着在这种情况下不会使用孩子的一些新功能。

If you do it the other way round and try to cast a base class to a child you would end up with an object that could live up the expectations on its interface.

如果你反过来做并尝试将基类转换为子类,你最终会得到一个可以满足其界面期望的对象。

For example you define a base class like:

例如,您定义一个基类,如:

Child extends Parent

 void doSomeSpecialChildStuff...

Now you create a Parent and assign it to a child object.

现在您创建一个 Parent 并将其分配给一个子对象。

Parent aParent = new Child()

Your programming language now thinks the aParent object is a Child. The problem is that now it would be perfectly valid to this:

您的编程语言现在认为 aParent 对象是一个 Child。问题是,现在它完全有效:

 aParent.doSomeSpecialChildStuff()

Now you are calling a method that isn't defined for the object but the interface of the object says it is defined.

现在您正在调用一个未为对象定义的方法,但对象的接口表示它已定义。

回答by erik

Think "inheritance" = "specialisation", although this seems counter-intuitive at first. The set of "Childs" is a subset of the set of "Parents" (you see that your example is a bit misleading). It naturally follows that a variable that can 'hold' a "Child" cannot a hold an abitrary member of the "Parent" set because it may not be in it the "Child" subset. On the other way, a variable that can 'hold' a "Parent" can hold every member of the "Child" set.

想想“继承”=“专业化”,尽管这乍一看似乎违反直觉。“Childs”集是“Parents”集的一个子集(你看到你的例子有点误导)。很自然地,可以“容纳”“子”的变量不能容纳“父”集合的任意成员,因为它可能不在“子”子集中。另一方面,可以“容纳”“父”的变量可以容纳“子”集的每个成员。

There seems to be 2 ways of viewing inheritance. On the programming level, "Child" is a superset of "Parent" abilities, as Kornel said. But conceptually, "Child" is a specialisation of "Parent" thus representing only a subset of all possible "Parent". Think for example "Vehicle" and "Car": a Car is a special Vehicle. The set of all Cars is still a subset of all vehicles. You may even "do more" with a Car than with a general Vehicle (e.g. changing tires, fill in gasoline etc.) but it's still a Vehicle.

似乎有两种查看继承的方式。正如 Kornel 所说,在编程层面上,“子项”是“父项”能力的超集。但从概念上讲,“孩子”是“父母”的特化,因此仅代表所有可能的“父母”的一个子集。例如“车辆”和“汽车”:汽车是一种特殊的车辆。所有汽车的集合仍然是所有车辆的子集。您甚至可以使用汽车比使用普通车辆“做更多”(例如更换轮胎、加注汽油等),但它仍然是车辆。