#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
показывает, что это действительно так.)
Итак, мои вопросы:
- Если
this
это действительно ссылкаClassB
, как я могу получить доступ к частной переменной экземпляраClassA
из метода, который принадлежитClassB
? classAMethod
На самом деле является членомClassA
иClassB
в момент выполнения?- Если ответ на 2. да, каковы правила для определения, в каком контексте будет выполняться любая данная строка в методе?
- Если ответ на 2. отрицательный, то какое альтернативное объяснение существует для поведения кода?
- Есть ли здесь какая-то большая картина или тонкость, которую я не могу оценить?
Комментарии:
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:
- Да,
this
относится к экземпляру ClassB, который также являетсяClassA
экземпляром. МетодclassAMethod
определен вClassA
и, следовательно, имеет доступ ко всемClassA
закрытым элементам. - Да,
classAMethod
это методClassA
, унаследованныйClassB
- Строка выполняется в контексте класса, в котором эта строка определена.
- Не применимо
Комментарии:
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
, вы получите сообщение об ошибке. Для этого переменная должна быть объявлена защищенной.