Why does is print last "I'm a Child Class." ?
public class Parent
{
String parentString;
public Parent()
{
System.out.println("Parent Constructor.");
}
public Parent(String myString)
{
parentString = myString;
System.out.println(parentString);
}
public void print()
{
System.out.println("I'm a Parent Class.");
}
}
public class Child extends Parent
{
public Child() {
super("From Derived");
System.out.println("Child Constructor.");
}
public void print()
{
super.print();
System.out.println("I'm a Child Class.");
}
public static void main(String[] args)
{
Child child = new Child();
child.print();
((Parent)child).print();
}
}
Output:
From Derived
Child Constructor.
I'm a Parent Class.
I'm a Child Class.
I'm a Parent Class.
I'm a Child Class.
Потому что это пример полиморфизма (позднее связывание). Во время компиляции вы указываете, что объект имеет тип Parent
и, следовательно, может вызывать только методы, определенные в Parent
. Но во время выполнения, когда происходит «привязка», метод вызывается для объекта, который имеет тип Child
, независимо от того, как на него ссылаются в коде.
Что вас удивляет, так это то, почему метод переопределения должен вызываться во время выполнения. В Java (в отличие от C # и C ++) все методы виртуальные и, следовательно, вызывается метод замены. См. этот пример , чтобы понять разницу.
Даже если вы приведете дочерний элемент к Parent, это не изменит его реализацию метода. На самом деле это не делает его родителем. Вот почему вы можете сделать что-то вроде:
Image img = new BufferedImage(...);
Несмотря на то, что Image является абстрактным, img по-прежнему является bufferedImage внизу.
Даже если вы преобразовываете его как родительский класс, это не означает, что он будет использовать свои родительские функции - он будет рассматривать объект только как родительский.
Сказав ((Parent) child) .print (); вы говорите: «Считайте этот объект родительским, а не дочерним». Не «Использовать реализации родительского метода»
Таким образом, если бы у дочернего объекта были другие методы, вы не смогли бы их вызвать. Но поскольку print () - это метод родительского объекта, вы все равно можете его вызвать, но он использует реализацию фактического объекта (а не класса, к которому он привязан).
Both:
child.print();
and
((Parent)child).print();
Should return:
I'm a Parent Class.
I'm a Child Class.
In that order.
Приведение объекта к его базовому классу не меняет того, какой вызов метода будет сделан.
В этом случае, даже после приведения, вызывается дочерний метод печати, а не родительский.