Java: наследование, переменные экземпляра и это

#java #inheritance #this

#java #наследование #это

Вопрос:

Я понял, что this это ссылка на выполняемый в данный момент объект. Если это так, можете ли вы объяснить поведение следующего кода?

 public class Inherit {

    public static class ClassA
    {
        private String privateInstanceVar = "Private";
        public void classAMethod()
        {
            System.out.println("In class: "   this.getClass().getName());
            System.out.println("Can access: "   this.privateInstanceVar);
        }
    }

    public static class ClassB extends ClassA
    {
    }

    public static void main(String[] args)
    {
        ClassB b = new ClassB();
        b.classAMethod();
        //Outputs:
        //In class: Inherit$ClassB
        //Can access: Private

        //System.out.println(b.privateInstanceVar); // Fails to compile
    }   
}
  

Первая строка classAMethod отчетов, на которую this ссылается ClassB . Однако в следующей строке я использую this для доступа к частной переменной privateInstanceVar экземпляра ClassA , к которой у меня не должно быть доступа. (Закомментированная последняя строка main показывает, что это действительно так.)

Итак, мои вопросы:

  1. Если this это действительно ссылка ClassB , как я могу получить доступ к частной переменной экземпляра ClassA из метода, который принадлежит ClassB ?
  2. classAMethod На самом деле является членом ClassA и ClassB в момент выполнения?
  3. Если ответ на 2. да, каковы правила для определения, в каком контексте будет выполняться любая данная строка в методе?
  4. Если ответ на 2. отрицательный, то какое альтернативное объяснение существует для поведения кода?
  5. Есть ли здесь какая-то большая картина или тонкость, которую я не могу оценить?

Комментарии:

1. Метод ClassA принадлежит классу A. Если вы переопределите этот метод в классе B, «privateInstanceVar» больше не будет доступен для этого метода.

Ответ №1:

Если это действительно ссылка на ClassB, как я могу получить доступ к частной переменной экземпляра в ClassA из метода, который принадлежит ClassB?

Потому что вы наследуете метод от ClassA, и этот метод обращается к частной переменной.

Является ли classAMethod на самом деле членом ClassA и ClassB в момент выполнения?

ДА

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

Контекст времени компиляции: будет выбран метод или поле, которое видно из кода, который вы пишете. Пример:

 public static class ClassA{
    private String foo = "bar";
    public String getFoo(){return foo;}
}
public static class ClassB extends ClassA{
    private String foo = "phleem";
}
  

new ClassB().getFoo() вернет «bar», а не «phleem», потому что ClassA не знает о ClassB.

Комментарии:

1. Шон, твое заявление о контексте времени компиляции очень полезно. Спасибо.

Ответ №2:

Я не уверен, в чем источник вашей путаницы. Это работает именно так, как и следовало ожидать:

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

http://download.oracle.com/javase/tutorial/java/IandI/subclasses.html

Комментарии:

1. Спасибо, Брайан. Это моя точка зрения — у меня не должно быть доступа к частной переменной экземпляра суперкласса из подкласса, но унаследованный метод, по-видимому, выполняющийся в контексте унаследованного подкласса, может получить к нему доступ. Я думаю, что ответ Шона рассеивает путаницу.

Ответ №3:

  1. Да, this относится к экземпляру ClassB, который также является ClassA экземпляром. Метод classAMethod определен в ClassA и, следовательно, имеет доступ ко всем ClassA закрытым элементам.
  2. Да, classAMethod это метод ClassA , унаследованный ClassB
  3. Строка выполняется в контексте класса, в котором эта строка определена.
  4. Не применимо

Комментарии:

1. Спасибо JB. Ваш ответ на вопрос 1, в котором говорится, что экземпляр ClassB также является экземпляром ClassA, помог прояснить мое мышление по этому поводу.

Ответ №4:

1) Поскольку ClassB наследуется от ClassA, поэтому все общедоступные, защищенные методы ClassA видны экземпляру ClassB.

2) Да.

3) если вы не переопределите classAMethod в ClassB, ClassB просто выполнит ClassA.classAMethod()

5) Это обычный способ наследования в Java.

Ответ №5:

ClassB имеет доступ classAMethod() , но у него нет доступа privateInstanceVar . Поэтому, если вы попытаетесь переопределить classAMethod() или даже определить какой-либо другой метод, который попытается получить доступ privateInstanceVar , вы получите сообщение об ошибке. Для этого переменная должна быть объявлена защищенной.