views:

2306

answers:

4

Let's start from another behavior: even if you declare method/variable as private, another instance of the same class can access it. It's OK I can live with it. I call these class private and not instance private.

Now the question part: For example, in runtime I want to be able to check that all String variables in this class are not null, and if they are null they should be changed to "NULL" string.

I run through the variables in reflection and get their values. But if I extend my class and add private or even protected variables my base class can't access them. I have to setAccessible on the variables before I can use it.

So please explain to me why the base-class (super-class) can't access private/protected variables from it's sub-class. It is its sub-class, so I don't get it. What's the idea behind this?

I know that super-class should not know about it's sub-classes, but in my example it makes sense, no?

Is it because I can't or shouldn't restrict my sub-classes in this way?


Update: Based on the answers, I want to know also: Why accessing another instance's private variables from the same class instance isn't considered violation of encapsulation ?

+1  A: 

It's as simple as it's a violation of encapsulation. Another class should not be able to reach into your class and be messing around with things, even if you generalize that class. How does a Vehicle know anything about a Car for example? The whole point of a base class is to provide for the sub-classes, but like an over-protective parent, what you're suggesting would be too much.

JP Alioto
Then why accessing another instance's private variables from the same class instance isn't considered violation of encapsulation ? Cars should be able to restrict BMWs to only have wheels and not wings, because if BMW has wings it's not a Car (even if it uses wings "internally")
Vitaly Polonetsky
Because I'm the class. You can't do what your talking about from outside the class, thus encapsulation is in tact. From within the class you can modify private members of another instance of the class. How is that a violation of anything? I'm in the class! I can change anything associated with the class I want, so why not allow it?
JP Alioto
+3  A: 

It's all about inheritance and encapsulation.

Java's visibility rules state that

  1. private members can only be accessed in the class that defines them
  2. protected members can only be access in
    • the class that defines them
    • subclasses of the class that defines them
    • other classes in the same package as the class that defines them

Of course, as you mention, in reflection you can change the rules (unless a SecurityManager forbids it)

Scott Stanchfield
Or, succinctly: This behavior is by design...
Tetsujin no Oni
@Tetsujin: you just made me smile ;)
Scott Stanchfield
Then why accessing another instance's private variables from the same class instance isn't considered violation of encapsulation ?
Vitaly Polonetsky
@Tetsujin Agree and I'm asking why the design is like this? Why it will be bad to have new modifier: unprotected, which is not public, for cases like this.
Vitaly Polonetsky
The encapsulation scheme in Java isn't instance-level encapsulation; it's class-level encapsulation. That's just the way most OO languages are implemented. It's not really a problem, as a single class is controlling data in all of its instances.
Scott Stanchfield
A: 

I tend to look it more from a pragmatic and realistic standpoint:

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; }
}

What syntax would you propose Test1 use to access private member a in Test2. When Test1 is written, Test2 may not even exist.

As well, a base-class (super-class) doesn't know when it has been inherited from. To allow a base-class to know when it has been inherited, you would have to be able to modify the base-class when inheriting from it. Are you suggesting that I should somehow modify my local copy of ArrayList when I write:

class MyArrayList extends ArrayList

And what happens the day I decide to run my code on your computer, do you get my modified copy of ArrayList that knows about MyArrayList, or do I modify the copy on your computer somehow?

Could these issues be overcome somehow? Certainly. Is there any value in allowing it? None that I can see.

Grant Wagner
In your example Test2 instance will actually have two variables: Test1.a and Test2.a, each accessible only from it's class. Test1 can change the value of Test1.a in Test2 instance, which is considered OK by the language, but will have no effect on Test2, even when Test1 "thinks" it does. There are many examples when subclass breaks compatibility when used as base-class. How is that different from what I'm asking?
Vitaly Polonetsky
I'm not sure what you're trying to say. I return to my original questions: 1) What sort of syntax could Test2 use to access or update private members of its parent class? 2) How does Test1 know how to expose its internal members to a class that may not have even been written yet? 3) How do you propagate the changes to the base class that has been modified to provide access to an inherited child? 4) Most importantly, what possible value could this provide to programmers?
Grant Wagner
1) Test2 can't access private members of the parent (that's what protected modifier is for). But Test1 can access "unprotected" (not private) members of Test1.2) protected does it3) that's the same as changing protected or private functions in base-class4) I'll write another question just to show the exact problem
Vitaly Polonetsky
+2  A: 

To answer your update question (as the original question is well answered already) the purpose of private is to hide implementation details so that those implementation details don't become dependencies. This is the essence of object oriented programing - encapsulation ensuring that complexity is kept manageable by keeping different parts isolated to their own area.

Since the class knows about its own implementation - it defines it, there is nothing gained in limiting access to other instances, since the class implementation declares all the private instances it is already exposed to all of these details.

Hiding it in this case would in fact increase complexity as you would have to add an additional access level to allow class-level visibility instead of instance level visibility without actually really encapsulating any further complexity.

Yishai