почему метод также должен быть в родительском, если в конце он напечатает содержимое дочернего

#java #inheritance #overriding #parent-child

Вопрос:

Родитель p = новый потомок(); Почему я не могу использовать метод print() в Родителе, не переопределяя его в Потомке?

 public class OverridingMethod {
    public static void main(String[] args) {
        Parent p = new Child();        
        // why this does not work
        p.print();
    }
}
 
class Parent{
    /*
    public void print(){
        System.out.println("Parent Method");
    }
    */
}
 
class Child extends Parent{
    public void print(){
        System.out.println("Child Method");
    }
}
 

Ответ №1:

 Parent p = new Child();
 

Здесь мы объявляем переменную с именем p . Его ценность такова new Child() . Что касается этой конкретной строки кода, мы создаем Child экземпляр. Однако вы назначили его переменной типа Parent . Это прекрасно; это называется повышением, и это фундаментальная часть полиморфизма, основанного на наследовании.

Однако, поскольку вы это сделали, компилятор распознает, что p это тип Parent . Во всех последующих строках кода Java забыла, что p на самом деле это a Child , и только предполагает, что это a Parent , так как вы сказали ему это предположить. Если Parent не знает , как print это сделать, то мы не можем print этого сделать, потому что мы сказали Java забыть, что у нас есть эта функциональность. Если Parent знает , как print это сделать, то мы можем print это сделать. То, как мы это печатаем, не имеет значения; подклассы могут переопределять это, если только метод не является final . Все, что имеет значение, — это то, что мы можем.

Теперь Java предоставляет нам бэкдоры в этот механизм. В теории, как только мы напишем

 Parent p = new Child();
 

после этой строки мы никогда не сможем осознать, что p это Child снова а. Мы сказали Java относиться к нему как к любому другому Parent . В общем, это хорошо. Если вы говорите , что что-то является а Parent , вы должны относиться к этому как к таковому. Если ты хочешь Child «а», тебе следовало попросить Child «а». Если нам действительно нужно, мы можем «обмануть» систему типов и посмотреть, что на самом деле в коробке.

 if (p instanceof Child) {
  Child c = (Child)p;
  ...
}
 

Теперь мы «восстановили» первоначального ребенка. Код, который часто использует описанную выше среду выполнения, проверяет, часто ли это признак плохо разработанной кодовой базы.