为什么我们将一个父引用分配给Java中的子对象?

我在问一个很简单的问题,但是我有点困惑。

假设我有一个class级Parent

 public class Parent { int name; } 

并有另一个类Child.java

 public class Child extends Parent{ int salary; } 

最后是我的Main.java类

 public class Main { public static void main(String[] args) { Parent parent = new Child(); parent.name= "abcd"; } } 

如果我做一个孩子的对象

 Child child = new Child(): 

然后, child对象可以访问name and salaryvariables。

我的问题是:

 Parent parent = new Child(); 

只给出Parent类的namevariables的访问权限。 那么这条线的确切用途是什么?

  Parent parent = new Child(); 

而且当它使用dynamic多态时,为什么在这样做后子类的variables是不可访问的

 Parent parent = new Child(); 

首先,澄清术语:我们将一个Child对象分配给一个Parenttypes的variables。 Parent是一个对象的引用,恰好是Parent一个子types。

它只是在一个更复杂的例子中有用。 想象一下,将getEmployeeDetails添加到类Parent:

 public String getEmployeeDetails() { return "Name: " + name; } 

我们可以在Child覆盖该方法来提供更多的细节:

 @Override public String getEmployeeDetails() { return "Name: " + name + " Salary: " + salary; } 

现在,您可以编写一行代码,获取任何可用的详细信息,无论该对象是Parent还是Child

 parent.getEmployeeDetails(); 

以下代码:

 Parent parent = new Parent(); parent.name = 1; Child child = new Child(); child.name = 2; child.salary = 2000; Parent[] employees = new Parent[] { parent, child }; for (Parent employee : employees) { employee.getEmployeeDetails(); } 

将导致输出:

 Name: 1 Name: 2 Salary: 2000 

我们用一个Child作为Parent 。 它具有对于Child类独特的专门行为,但是当我们调用getEmployeeDetails()我们可以忽略差异,并重点关注ParentChild是如何相似的。 这被称为亚型多态性 。

您更新后的问题会询问为什么Child.salaryChild对象存储在Parent引用中时不可访问。 答案是“多态”和“静态types”的交集。 由于Java在编译时是静态types的,所以你可以从编译器得到一定的保证,但是你不得不遵循交换规则或者代码不能编译。 在这里,相关的保证是子types(例如Child )的每个实例都可以用作其超types的一个实例(例如Parent )。 例如,您可以保证,当您访问employee.getEmployeeDetailsemployee.name ,方法或字段将定义在任何可以分配给Parenttypes的variablesemployee的非null对象上。 为了保证这一点,编译器在决定你可以访问什么的时候只考虑那个静态types(基本上是variables引用的types, Parent )。 因此,您无法访问在对象的运行时typesChild上定义的任何成员。

当你真的想要使用一个Child作为Parent这是一个容易的限制住,你的代码将可用于Parent及其所有子types。 当不能接受的时候,制作参考Child的types。

它允许你通过一个公共的父接口访问所有的子类。 这对于运行所有子类上可用的通用操作是有益的。 需要一个更好的例子:

 public class Shape { private int x, y; public void draw(); } public class Rectangle extends Shape { public void draw(); public void doRectangleAction(); } 

现在如果你有:

 List<Shape> myShapes = new ArrayList<Shape>(); 

您可以将列表中的每个项目都引用为一个Shape,您不必担心它是否为Rectangle或其他types,比如说Circle。 你可以一视同仁 你可以把他们全部画出来。 你不能调用doRectangleAction,因为你不知道Shape是否真的是一个矩形。

这是一种以通用方式处理对象和专门处理对象之间的交易。

真的,我认为你需要阅读更多关于OOP。 一本好书应该帮助: http : //www.amazon.com/Design-Patterns-Explained-Perspective-Object-Oriented/dp/0201715945

如果将父types分配给子类,则意味着您同意使用父类的公共特征。

它使您可以自由地从不同的子类实现中进行抽象。 结果限制了你的父function。

然而,这种types的任务被称为上传。

 Parent parent = new Child(); 

相反是倒下。

 Child child = (Child)parent; 

因此,如果您创buildChild实例并将其向下转换为Parent ,则可以使用该types的属性name 。 如果您创buildParent实例,则可以执行与之前的情况相同的操作,但不能使用salary因为Parent没有这样的属性。 返回到可以使用salary的前一个案例,但只有在向下转换为Child

有更详细的解释

在编译程序时,基类的引用variables会获取内存,编译器会检查该类中的所有方法。 所以它检查所有的基类方法,而不是子类方法。 现在,在运行时创build对象时,只能运行已检查的方法。 在函数运行的子类中覆盖函数的情况。 Child class其他函数不运行coz编译器在编译时没有识别它们。

假设你想拥有一个Parent类实例的数组,并且有一组子类Child1,Child2,Child3可以扩展Parent。 有时你只对父类实现感兴趣,而这个实现更通用,并且不关心子类引入的更具体的东西

这种情况发生在你有几个实现。 让我解释。 假设你有几种sortingalgorithm,你想在运行时select一个实现,或者你想给别人添加他的实现的能力。 为了解决这个问题,你通常创build一个抽象类(Parent)并且有不同的实现(Child)。 如果你写:

 Child c = new Child(); 

你将你的实现绑定到Child类,你不能再改变它。 否则,如果你使用:

 Parent p = new Child(); 

只要Child扩展Parent,您就可以在将来修改代码。

同样的事情可以使用接口完成:父不再是一个类,而是一个Java接口。

一般来说,您可以在DAO模式中使用这种方式,在这种方式中,您希望有几个与数据库相关的实现。 你可以看看FactoryPatter或AbstractFactory模式。 希望这可以帮到你。

这很简单。

 Parent parent = new Child(); 

在这种情况下,对象的types是Parent 。 antParent只有一个属性。 这是name

 Child child = new Child(); 

在这种情况下,对象的types是Child 。 antChild有两个属性。 他们是namesalary

事实是,在声明中不需要立即初始化非final字段。 通常这是在运行时完成的,因为通常你不知道到底需要什么实现。 举个例子,假设你有一个头部类Transport的类层次结构。 还有三个小类: CarHelicopterBoat 。 还有另外一个有现场Transport课程。 那是:

 class Tour { Transport transport; } 

只要用户没有预定旅程,也没有select特定types的交通工具,则无法初始化该字段。 这是第一个。

其次,假设所有这些类都必须有一个方法go()但是具有不同的实现。 您可以在超类Transport默认定义一个基本实现,并在每个子类中拥有唯一的实现。 通过这个初始化Transport tran; tran = new Car(); Transport tran; tran = new Car(); 你可以调用tran.go()方法并得到结果,而不用担心具体的实现。 它会从特定的子类调用overrided方法。

而且你可以在任何使用超类的实例的地方使用子类的实例。 例如,你想提供机会租用你的交通工具。 如果你不使用多态,你必须为每个案例写很多方法: rentCar(Car car)rentBoat(Boat boat)等等。 同时多态可以让你创build一个通用的rent(Transport transport) 。 你可以传入任何Transport子类的对象。 另外,如果随着时间的推移,你的逻辑会增加,你需要在层次结构中创build另一个类。 当使用多态时,你不需要改变任何东西。 只需扩展类Transport然后将新类传入方法:

 public class Airplane extends Transport { //implementation } 

rent(new Airplane()) 。 和new Airplane().go()第二种情况。

你声明parent为Parent,所以java将只提供Parent类的方法和属性。

 Child child = new Child(); 

应该pipe用。 要么

 Parent child = new Child(); ((Child)child).salary = 1;