вопрос о сокрытии / скрытии переменных-членов в Java - PullRequest
1 голос
/ 25 июня 2011

Я хочу понять, как работает скрытие в Java.Итак, давайте предположим, что у вас есть следующий код

public class A{
    protected SomeClass member;
    public A(SomeClass member){
        this.member = member;
    }
}  

public class B extends A{
    protected SomeClass member;
    public B(SomeClass member){
        super(member);
    }
    public static void main(String[] args){
        SomeClass sc = new SomeClass();
        B b = new B(sc);
        System.out.println(b.member.toString());
    }
}

Если я скомпилирую, я получу честь NullPointerException.Я думал, что это будет вывод sc.toString ();

Я изменяю этот код на

public class A{
    protected SomeClass member;
    public A(SomeClass member){
        setMember(member);
    }
    public void setMember(SomeClass sc){
       this.member = sc;
    }

}  

public class B extends A{
    protected SomeClass member;
    public B(SomeClass member){
        super(member);
    }
    public void setMember(SomeClass sc){
       this.member = sc;
    }
    //...main
}

, и он получит вывод, как ожидалось ... ok setMember of B Переопределяетодин из А, так что я могу объяснить это таким образом.Я немного поигрался и удалил setMember из B, чтобы получить обратно свое NullPointerException.Но он компилируется снова и дает мне вывод, если я изменяю код А на

public class A{
    protected SomeClass member;
    public A(SomeClass member){
        setMember(member);
    }
    public void setMember(SomeClass sc){
       member = sc;
    }

} 

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

1 Ответ

3 голосов
/ 25 июня 2011

Я предполагаю, что вы имели в виду, что последняя строка первого примера кода была b.member.toString().

Есть две переменные-члены с именем "member", и в обоих ваших примерах устанавливается только одна из них, поскольку вызывается только одно присваивание this.member. Чтобы исправить первый пример, вы обычно говорите

public B(SomeClass member) {         
    super(member);
    this.member = member;
} 

Но я думаю, что вы уже понимаете это и действительно спрашиваете, почему язык разработан таким образом. Это связано с инкапсуляцией реализации суперкласса. Автор суперкласса должен иметь возможность переписать его, не нарушая подклассы, и наоборот. Представьте себе, если бы B.member появился первым, потому что автору B было бы неплохо иметь «члена», а позже у автора A возникла та же мысль.

Однако эта система не идеальна, и ваш второй пример показывает, почему. Если сначала пришел B.setMember(), а затем более поздняя версия A вводит A.setMember(), то автору A может не предвидеть переопределенный метод B.setMember() и написать конструктор так, как вы показываете, в результате чего A.member никогда не инициализируется. C # ввел ключевое слово «overrides», чтобы поймать подобные вещи, а Java заимствовал его как «@overrides», но эта аннотация не является обязательной в Java, поэтому она не так эффективна.

...