В Java, почему метод суперкласса не может получить доступ к защищенным или закрытым методам / переменным из экземпляра подкласса? - PullRequest
7 голосов
/ 22 мая 2009

Давайте начнем с другого поведения: даже если вы объявите метод / переменную как private, другой экземпляр того же класса может получить к нему доступ. Это нормально, я могу жить с этим. Я называю эти классы частными, а не частными экземплярами.

Теперь часть вопроса: Например, во время выполнения я хочу иметь возможность проверить, что все переменные String в классе this не равны NULL, и если они равны NULL, их следует заменить на строку «NULL».

Я могу пробежаться по переменным с помощью отражения и получить их значения. Но если я расширю свой класс и добавлю приватные или даже защищенные переменные, мой базовый класс не сможет получить к ним доступ. Мне нужно setAccessible для переменных, прежде чем я смогу их использовать.

Поэтому, пожалуйста, объясните мне, почему базовый класс (суперкласс) не может получить доступ к закрытым / защищенным переменным из своего подкласса. Это его подкласс, поэтому я не понимаю. Что за идея стоит за этим?

Я знаю, что суперкласс не должен знать о своих подклассах, но в моем примере это имеет смысл, нет?

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


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

Ответы [ 4 ]

7 голосов
/ 23 мая 2009

Чтобы ответить на ваш вопрос об обновлении (так как на исходный вопрос уже получен хороший ответ), цель private - скрыть детали реализации, чтобы эти детали реализации не стали зависимостями. В этом суть объектно-ориентированного программирования - инкапсуляция, обеспечивающая управление сложностью за счет изоляции отдельных частей от собственной области.

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

Сокрытие этого в этом случае фактически увеличило бы сложность, поскольку вам пришлось бы добавить дополнительный уровень доступа, чтобы обеспечить видимость на уровне класса вместо видимости на уровне экземпляра, фактически не инкапсулируя какую-либо дополнительную сложность.

7 голосов
/ 22 мая 2009

Это так же просто, как нарушение инкапсуляции. Другой класс не должен быть в состоянии проникнуть в ваш класс и возиться с вещами, даже если вы обобщаете этот класс. Откуда Автомобиль знает что-нибудь об автомобиле, например? Весь смысл базового класса состоит в том, чтобы обеспечить подклассы, но, как и родитель-защитник, вы предлагаете слишком много.

4 голосов
/ 22 мая 2009

Все дело в наследовании и инкапсуляции.

В правилах видимости Java указано, что

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

Конечно, как вы упомянули, вы можете изменить правила (если только SecurityManager не запрещает это)

0 голосов
/ 22 мая 2009

Я склонен смотреть на это более прагматично и реалистично:

public class Test1 {
    private int a = 1;

    public static void main(String s[]) {
        System.out.println((new Test1()).a);
        System.out.println((new Test1()).getA());
        System.out.println((new Test2()).getA());
    }

    public int getA() { return a; }
}

class Test2 extends Test {
    private int a = 2;

    public int getA() { return a; }
}

Какой синтаксис вы бы предложили Test1 использовать для доступа к приватному члену a в Test2. Когда написано Test1, Test2 может даже не существовать.

Кроме того, базовый класс (суперкласс) не знает, когда он был унаследован от. Чтобы базовый класс мог знать, когда он был унаследован, вы должны иметь возможность изменять базовый класс при наследовании от него. Вы предлагаете мне как-то изменить мою локальную копию ArrayList, когда я пишу:

class MyArrayList extends ArrayList

И что произойдет в тот день, когда я решу запустить свой код на вашем компьютере, вы получите мою модифицированную копию ArrayList, которая знает о MyArrayList, или я каким-то образом изменю копию на вашем компьютере?

Можно ли как-то преодолеть эти проблемы? Конечно. Есть ли какая-то ценность в разрешении этого? Нет того, что я вижу.

...