2015-09-07 3 views
3

Пример кода:Понимание модели наследования в Java

public class Parent { 
    String name = "Parent"; 

    public String getName() { 
    return this.name; 
    } 
} 

public class Child extends Parent { 
    String name = "Child"; 

    public String getName() { 
    return this.name; 
    } 
} 

public class Tester { 
    public static void main (String[] args) { 
    Parent p = new Child(); 
    Child c = new Child(); 
    System.out.println("p.name is " + p.name); // prints out "Parent" 
    System.out.println("c.name is " + c.name); // prints out "Child" 
    System.out.println("p.getName() is " + p.getName()); // prints out "Child" 
    System.out.println("c.getName() is " + c.getName()); // prints out "Child" 
    } 
} 

Мое понимание So Far

До сих пор мое понимание наследования в Java позволяет мне понять, почему третья и 4-й println заявления производят «ребенка "как выход. Во время компиляции компилятор должен убедиться, что метод getName определен в типе ссылочной переменной, но во время выполнения определяется, какая версия getName определена. И поскольку обе ссылочные переменные на самом деле относятся к объекту Child, вызывается Child's getName.

Вопрос 1

Однако, почему это, что, когда вы получаете доступ к переменной экземпляра напрямую, поведение отличается от того, как методы доступны? В частности, мне показалось странным, что p.name возвращает «Родитель» вместо «Ребенок».

Вопрос 2

В том же духе, если я закомментировать функции getName в Child классе и вновь побежал код в Tester, я удивлен, что p.getName() и c.getName() возвращение «Родитель «вместо« Ребенок ».

Может кто-нибудь помочь в разработке этих двух вопросов?

+2

Вся проблема, с которой вы сталкиваетесь, заключается в том, что вы считаете, что можете также перезаписать переменные, но вы не можете. check [this] (http://stackoverflow.com/questions/7794621/hiding-instance-variables-of-a-class) – SomeJavaGuy

+1

Спасибо, что поделились этой ссылкой @KevinEsche!Как это относится к моему второму вопросу? – wmock

+0

Кроме того, наследование описывает отношение * является *. По этой причине аналогия «Родительская»/«Ребенок» ужасно плоха. «Ребенок» * не * «Родитель». – aioobe

ответ

4

Переменные не могут быть переопределены в Java. То, что вы сделали, называется скрывает переменную (переменная name в Parent трудно получить доступ)

Путь, чтобы понять поведение, которое вы описываете, это думать о name, как только имя переменной, а не фактической переменной , При использовании в контексте (с точки зрения кода, а не фактического типа переменной) Parent он указывает на другую переменную, чем при использовании в контексте Child.

При вызове c.name или p.name вы скажите программу, которая контекст использования, поскольку переменные c и p объявляются соответственно типа Child и Parent. При использовании в методе внутри класса используется переменная текущего класса.

Если вы хотите использовать Parent.name в классе ребенка вам придется бросить его:

System.out.println("c.name is " + ((Parent) c).name); 

Для метода, функция называется всегда, что фактического типа переменной вызывается. В вашем случае, независимо от его вызова от Tester, Parent или Client.

Конечно, лучше не скрывать переменные вообще, использовать разные имена для разных переменных.

+0

Спасибо за разъяснение @Тирлер - это имеет смысл для меня сейчас. – wmock

Смежные вопросы