В Java, почему метод суперкласса не может получить доступ к защищенным или закрытым методам / переменным из экземпляра подкласса?
Давайте начнем с другого поведения: даже если вы объявите метод / переменную как private, другой экземпляр того же класса может получить к нему доступ. Это нормально, я могу жить с этим. Я называю это частным классом, а не частным экземпляром.
Теперь часть вопроса: например, во время выполнения я хочу иметь возможность проверить, что все переменные String в this
класс не является нулевым, и если они являются нулевыми, они должны быть заменены на строку "NULL".
Я могу пробежаться по переменным с помощью отражения и получить их значения. Но если я расширю свой класс и добавлю приватные или даже защищенные переменные, мой базовый класс не сможет получить к ним доступ. Мне пришлось setAccessible
на переменные, прежде чем я смогу их использовать.
Поэтому, пожалуйста, объясните мне, почему базовый класс (суперкласс) не может получить доступ к закрытым / защищенным переменным из своего подкласса. Это его подкласс, поэтому я не понимаю. Что за идея стоит за этим?
Я знаю, что суперкласс не должен знать о своих подклассах, но в моем примере это имеет смысл, нет?
Это потому, что я не могу или не должен ограничивать свои подклассы таким образом?
Обновление: основываясь на ответах, я хочу знать также: почему доступ к закрытым переменным другого экземпляра из того же класса не считается нарушением инкапсуляции?
4 ответа
Это так же просто, как и нарушение инкапсуляции. Другой класс не должен быть в состоянии проникнуть в ваш класс и возиться с вещами, даже если вы обобщаете этот класс. Откуда Автомобиль знает что-нибудь об автомобиле, например? Весь смысл базового класса состоит в том, чтобы обеспечить подклассы, но, как родитель с чрезмерной защитой, вы предлагаете слишком много.
Чтобы ответить на ваш вопрос об обновлении (поскольку на первоначальный вопрос уже получен хороший ответ), цель private - скрыть детали реализации, чтобы эти детали реализации не стали зависимостями. В этом суть объектно-ориентированного программирования - инкапсуляция, обеспечивающая управление сложностью за счет изоляции различных частей от их собственной области.
Так как класс знает о своей собственной реализации - он определяет ее, нет ничего полезного в ограничении доступа к другим экземплярам, так как реализация класса объявляет все частные экземпляры, которые уже доступны всем этим деталям.
Сокрытие этого в этом случае фактически увеличило бы сложность, поскольку вам нужно было бы добавить дополнительный уровень доступа, чтобы позволить видимость на уровне класса вместо видимости уровня экземпляра, фактически не инкапсулируя какую-либо дополнительную сложность.
Все дело в наследовании и инкапсуляции.
Правила видимости Java утверждают, что
- частные члены могут быть доступны только в классе, который их определяет
- защищенные члены могут быть доступны только в
- класс, который их определяет
- подклассы класса, который их определяет
- другие классы в том же пакете, что и класс, который их определяет
Конечно, как вы упомянули, в рефлексии вы можете изменить правила (если только SecurityManager не запрещает это)
Я склонен смотреть на это более прагматично и реалистично:
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
Или я как-то изменяю копию на вашем компьютере?
Можно ли как-то преодолеть эти проблемы? Конечно. Есть ли какая-то ценность в разрешении этого? Ничего такого, что я вижу.