В Java, почему защищенный член может получить доступ из-за пределов класса внутри одного пакета?

В своей книге Герберт Шильдт говорит на стр. 172 (3-й абзац), что " protected применяется только при наследовании".

На стр. 228 в таблице 9-1 показано, что к защищенному члену можно получить доступ из непод-класса в одном пакете.

Следующий код работает и поддерживает информацию в таблице 9-1.

Class1.java:

package Mypack;
public class Class1
{
    protected pro=1;
    public Class1()
    {
        System.out.println(pro);
    }
}

Class2.java

package Mypack;
class Class2 extends Class1
{
    Class2()
    {
        System.out.println(pro);
    }
}

Class3.java

package Mypack;
class Class3
{
    Class3()
    {
        Class1 class1=new Class1();
        System.out.println(class1.pro);
    }
}

Хорошо, что переменную pro можно получить из производного класса Class2. Но как можно получить доступ из не производного класса Class3 через ссылку на объект класса 1? Это противоречит утверждению на стр. 172. Если это так, то я не вижу разницы между публичными и защищенными спецификаторами в этой ситуации.

Ответы

Ответ 1

В своей книге Герберт Шильдт говорит на стр. 172 (3-й абзац), что "защита применяется только при наследовании".

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

Modifier    Class  Package  Subclass  World
public        Y       Y        Y       Y
protected     Y       Y        Y       N
no modifier   Y       Y        N       N
private       Y       N        N       N

Обратите внимание, что ни один модификатор не предоставляет доступ к классу и пакету члену и не предоставляет доступ к подклассам или миру. protected изменяет только одну из этих вещей: он делает доступным элемент для подклассов. Поэтому в этом смысле он исправляет: применяется только при наследовании; без наследования, он не имеет модификатора.

Но я нахожу это довольно вводящим в заблуждение, по той самой причине, которая вызвала ваш вопрос: кажется, подразумевает, что доступа к пакетам не будет. Единственный способ, который имеет смысл в заявлении, заключается в том, что вы уже знаете, что никакой модификатор не предоставляет доступ к пакету.

Для ясности: protected означает, что член доступен для любого класса в пакете и для кода в подклассах. Это позволяет библиотеке иметь поля и методы, из которых вы получаете доступ только от кода, который является частью библиотеки * (вид, см. Ниже) или код, который помогает реализовать что-то в библиотеке (например, если вы являетесь подклассом из один из классов библиотеки). Нет особого "почему", кроме того, как был разработан язык.

Если это так, я не вижу разницы между публичными и защищенными спецификаторами в этой ситуации.

В этой ситуации нет. Очевидно, что очень большая разница, однако, когда вы рассматриваете код, который не находится в одном пакете и не находится в производном классе члена пакета: этот код не имеет доступа к членам protected.

Это описано в JLS§6.6.1:

... если член или конструктор объявлен protected, тогда доступ разрешен только тогда, когда выполняется одно из следующих условий:

  • Доступ к члену или конструктору происходит изнутри пакета, содержащего класс, в котором объявлен защищенный член или конструктор.

  • Доступ является правильным, как описано в разделе 6.6.2.

(обратите внимание на первую пулю) и JLS§6.6.2:

A protected член или конструктор объекта может быть доступен извне пакета, в котором он объявляется только кодом, ответственным за реализацию этого объекта.

( "код, который отвечает за реализацию этого объекта"; — например, код в подклассе.)


* Повторите мой "вид", см. ниже "on". Это позволяет библиотеке иметь поля и методы, из которых вы получаете доступ только от кода, который является частью библиотеки... "Это не так, потому что, за исключением ограниченные пакеты (например, java.lang), вы можете с радостью написать свой собственный класс, говорящий об этом в библиотечном пакете, а затем использовать поля уровня пакета и методы классов библиотеки. Концепция пакета Java не является механизмом защиты полей/методов.

Ответ 2

Защищенный модификатор указывает, что к члену можно получить доступ только в своем собственном пакете (например, в пакете-private) и, кроме того, подклассе его класса в другом пакете. https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

Ответ 4

В таблице на этой ссылке показаны модификаторы, по сравнению с которыми http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html можно получить доступ. Модификатор затем выбирается на основе таких факторов, как то, что нужно скрывать от другого класса, что нужно делиться в соответствии с хорошими принципами, такими как инкапсуляция и т.д.

Уровни доступа

Класс подклассов класса-подкласса

public Y Y Y Y

защищенный Y Y Y N

нет модификатора Y Y N N

частный Y N N N

Ответ 5

Если это так, то я не вижу разницы между общественностью и защищенные спецификаторы в этой ситуации

Это правильно, в этой ситуации нет разницы.
Рассмотрим этот код:

package otherpack;
public class Class4
{
    Class4()
    {
        Class1 class1=new Class1(); // Ok, Class1 and it constructor are public
        System.out.println(class1.pro); // Compilation error. pro is protected
    }
}

package otherpack;
public class Class5 extends Class1
{
    Class5()
    {
        Class1 class1=new Class1(); // Ok, Class1 and it constructor are public
        System.out.println(class1.pro); // OK, Class5 extends Class1 and pro is protected
    }
}

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