Java: защищенное ограничение доступа для подкласса объекта суперкласса
Я знаю, что это было задано ранее на этом форуме, но я попрошу снова, так как я не вижу никакого хорошего ответа (пока).
Вот он:
package a;
public class A{
protected int a;
}
package b;
public class B extends A{
}
package c;
public class C extends B{
public void accessField(){
A ancient = new A();
ancient.a = 2; //A - That wouldn't work.
a = 2; //B - That works.
}
}
Почему статья А) не будет работать? Какова рациональность этого ограничения для старинного доступа к суперклассу в подклассе C?
Спасибо.
Ответы
Ответ 1
Защищенные члены могут быть доступны только за пределами того же пакета, если это через наследование, то есть внутри иерархии.
Итак, когда вы создаете еще один экземпляр A из другого пакета, это не отношение наследования, и он таким образом терпит неудачу.
Как всегда, это описано в JLS, 6.6.2:
Защищенный член или конструктор объекта может быть доступен извне пакета, в котором он объявляется только кодом, ответственным за реализацию этого объекта.
Ответ 2
На самом деле вам не нужны два уровня наследования, а приведенный ниже код приведет к такому же поведению:
public class B extends A{
public void accessField() {
A ancient = new A();
ancient.a = 2; //A - That wouldn't work.
a = 2; //B - That works.
}
}
Причина, по которой работает a = 2
, - JLS 6.2.2.1:
Пусть C - класс, в котором объявлен защищенный член. Доступ разрешен только в пределах тела подкласса S из C.
Обратите внимание, что он не говорит прямого подкласса, а только подкласса. Поэтому a = 2
работает в классе B
или C
.
С другой стороны, ancient.a = 2;
покрывается следующей маркерной точкой в том же разделе:
Если доступ осуществляется по квалифицированному имени Q.Id, где Q - имя ExpressionName, то доступ разрешен только тогда, когда тип выражения Q является S или подклассом S.
В вашем случае Q.Id
есть ancient.a
= > , он будет доступен, только если тип ancient
был B
или подкласс B
. Так, например, это скомпилировалось бы:
public class B extends A{
public void accessField() {
C ancient = new C();
ancient.a = 2; //A - That wouldn't work.
}
}
Ответ 3
Цитата из книги Язык программирования Java 3 изд. Gosling et all - стр. 81 с. 3.5
"Что защищено на самом деле означает" -.. за пределами доступа к самому классу и для кода внутри одного и того же пакета, защищенный член также может быть доступен из класса через ссылки на объекты, которые имеют atleast того же типа, что и класс, - это ссылки типа класса или одного из его подклассов
Ответ 4
Цитата из JLS 6.6.2
Защищенный член или конструктор объекта может быть доступен извне пакета, в котором он объявляется только кодом, ответственным за реализацию этого объекта.
Когда вы говорите,
A ancient = new A();
ancient.a = 2;
вы ничего не наследуете от древнего (объект A) и, следовательно, не отвечаете за его реализацию. Сделав C extends A, вы уже унаследовали 'a' от другого объекта A, следовательно, приведенное ниже описание работает.
a = 2;
Если,
ancient.a = 2;
работает, тогда нет никакой разницы между публичным и частным спецификатором доступа.