2015-07-24 4 views
0

Может кто-нибудь объяснить мне, что здесь происходит и ПОЧЕМУ?Наследование и динамическое связывание

class Base{ 
    private float f = 1.0f; 
    void setF(float f1){ this.f = f1; } 
    float getF() {return f;} 
    public void xx(){} 
} 

class Base2 extends Base{ 
    private float f = 2.0f; 

    public void xx(){ 
     System.out.println(super.getF()+" "+this.getF()); 
    } 

    //float getF() {return f;} //1 
    //void setF(float f1){ this.f = f1; } //2 

    public static void main(String[]args){ 
     Base b=new Base2(); 
     b.setF(3); 
     b.xx(); 
     System.out.println(b.getF()); 
     System.out.println(((Base)b).getF()); 
    } 
} 

Выход этого кода будет 3 3, 3, 3.

Если я раскомментировал только линию 1 с геттером, выход будет 3 2, 2, 2.

Если я раскомментировал только линию 2 с сеттером, выход будет 1 1, 1, 1.

Если я раскомментирую обе линии 1 и 2 (с сеттером и геттером), выход будет 1 3, 3, 3.

 //default output: 3 3, 3, 3 
     //with getter: 3 2, 2, 2 
     //with setter: 1 1, 1, 1 
     //with getter and setter: 1 3, 3, 3 

Если переопределить метод в родительском классе с кодом в подклассе, что метод коррекции не может получить доступ к переменной-члена, даже если переопределяется метод в родительском делает. Однако переопределяющий метод в подклассе может вызвать переопределенный метод в родительском.

Таким образом, это объяснить, дело № 4 и с геттер и сеттер, которые имеют доступ только к переменной-члена Base2

ответ

1

Вы получаете 3 3 3 3, потому что установить/получить методы модифицирует Base.f переменную:

Вы получаете 3 2 2 2, потому что значение изменения Base.f, но метод get получает значение переменной Base2.f.

Вы получаете 1 1 1 1, потому что значение метода изменения метода Base2.f, но метод get получает значение переменной Base.f.

Вы получаете 1 3 3 3, потому что super.getF() возвращает значение Base.f переменной, но другие методы get возвращают значение переменной Base2.f. Также значение изменения метода установки изменяется от Base2.f.

+0

Почему в случае № 1 (без геттера и сеттера в подклассе) setF (3) меняет как Base.f, так и Base2. е? – anastsiacrs

+0

@anastsiacrs 'setF (3)' изменять только 'Base.f'. Getter и setter определяются только в классе «Base», поэтому, когда они выполняются, они получают/устанавливают значение «Base.f» varaible. «Base2.f» не изменяется, поэтому в случае №2 (где вы переопределяете метод getter) вы получаете «3 2 2 2' – lukaslew

+0

case # 1: если setF (3) меняет только Base.f, то почему. f (в методе xx()) return 3? – anastsiacrs

1

Давайте начнем с некоторого фона.

В Inheritance Java учебник говорится:

Частные члены суперкласса

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

В Polymorphism главе говорится:

Виртуальная машина Java (JVM) вызывает соответствующий метод для объекта, на который ссылается в каждой переменной. Он не вызывает метод , который определяется типом переменной.Это поведение называется вызов виртуального метода и демонстрирует аспект важных функций полиморфизма на языке Java.

Наконец, в Hiding fields главе того же учебника говорится:

В классе, поле, которое имеет такое же имя, как поле в суперкласса скрывает поле суперкласса, даже если их типы разные. Внутри подкласса поле в суперклассе не может быть , на которое ссылается его простое имя. Вместо этого поле должно быть обращено к через супер, которое рассматривается в следующем разделе. Обычно говоря, мы не рекомендуем скрывать поля, так как это затрудняет код .

Таким образом, подкласс не имеет доступа к частным членам суперкласса напрямую. Тем не менее, они все еще существуют и могут быть доступны или изменены с помощью неличных accessors/mutators.

Теперь вернемся к самому вопросу.

В первом примере вы не применяете ни аксессуар, ни мутатор - вы просто вызываете унаследованные все время. Они возвращают и изменяют значение f of Base. Почему унаследованный аксессор/мутатор не возвращает/не изменяет значение f of Base2? Потому что даже если f базы не был закрытым, он не был бы отменен, а просто скрыт.

Во втором примере вы переопределяете аксессор. Здесь вы начинаете вовлекать полиморфизм. This short answer может быть полезно для понимания. Когда вы вызываете b.setF(3), вы устанавливаете значение f of Base. Однако, когда вы вызываете getF(), вы получаете значение f of Base2, за исключением случая, когда вы позвоните по ключевому слову super. Пожалуйста, обратите внимание, что в последнем вызове System.out.println(((Base)b).getF()) литейного базы ничего не делает, так как б уже объявлен как базы. Вы не можете вызвать переопределенный метод суперкласса без использования super (как вы уже знаете, только методы экземпляра могут быть переопределены).

В третьем примере вы переопределите мутатор. Ситуация противоположна вашему второму примеру. Когда вы вызываете b.setF(3), вы устанавливаете значение f Base2. Но вы всегда получаете f из Base от геттера, потому что геттер не переоценивается. Таким образом, все 4 обращения к getF() возвращают начальное значение f of Base.

В последнем примере вы переопределяете как аксессуар, так и мутатор. Поэтому они работают на f Base2. Единственным вызовом, возвращающим начальное значение f из Base, является, очевидно, super.getF().

Это, безусловно, не идеальное объяснение, но я надеюсь, что это поможет.

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