2009-05-22 2 views
7

Начнем с другого поведения: даже если вы объявите метод/переменную приватным, другой экземпляр того же класса может получить к нему доступ. Это нормально, я могу жить с этим. Я называю это class-private, а не private-instance.В Java почему метод суперкласса не может получить доступ к защищенным или приватным методам/переменным из экземпляра подкласса?

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

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

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

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

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


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

+2

нет, это не имеет смысла. –

ответ

7

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

+0

Тогда почему доступ к частным переменным другого экземпляра из одного экземпляра класса не считается нарушением инкапсуляции? Автомобили должны быть в состоянии ограничить BMW только колеса, а не крылья, потому что, если у BMW есть крылья, это не автомобиль (даже если он использует крылья «внутренне») –

+1

Потому что я класс. Вы не можете делать то, о чем говорите, вне класса, поэтому инкапсуляция происходит в такте. Изнутри класса вы можете модифицировать частные члены другого экземпляра класса. Как это нарушение чего-либо? Я в классе! Я могу изменить все, что связано с классом, который я хочу, так почему бы не позволить это? –

4

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

правила видимости в Java утверждают, что

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

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

+1

Или, лаконично: это по дизайну ... –

+0

@Tetsujin: вы только что заставили меня улыбнуться;) –

+0

Тогда почему доступ к частным переменным другого экземпляра из одного экземпляра класса не считается нарушением инкапсуляции? –

0

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

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, или я могу каким-то образом изменить копию на вашем компьютере?

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

+0

В вашем примере экземпляра Test2 фактически будут две переменные: Test1.a и Test2.a, каждая из которых доступна только из класса. Test1 может изменить значение Test1.a в экземпляре Test2, который считается языком OK, но не будет влиять на Test2, даже если Test1 «думает» о нем. Существует много примеров, когда подкласс прерывает совместимость при использовании в качестве базового класса. Как это отличается от того, что я спрашиваю? –

+0

Я не уверен, что вы пытаетесь сказать. Я возвращаюсь к своим оригинальным вопросам: 1) Какой синтаксис мог использовать Test2 для доступа или обновления частных членов его родительского класса? 2) Как Test1 знает, как подвергать своих внутренних членов классу, который еще не был написан? 3) Как вы распространяете изменения в базовый класс, который был изменен для обеспечения доступа к унаследованному ребенку? 4) Самое главное, какое возможное значение может предоставить программистам? –

+0

1) Test2 не может получить доступ к закрытым членам родителя (для этого используется защищенный модификатор). Но Test1 может получить доступ к «незащищенным» (не закрытым) членам Test1. 2) защищено 3) это то же самое, что изменение защищенных или частных функций в базовом классе 4) Я напишу еще один вопрос, чтобы показать точную проблему –

7

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

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

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