1

Why is it that I have access to and visibility of protective fields inside classes that share the same parent? I always figured that protected could only be accessed through the parent or the child itself not outside in any way.

class Parent {

    protected int age;
}

class Sister extends Parent { }

class Brother extends Parent {

    public void myMethod(Sister sister) {
        //I can access the field of my sister,
        // even when it is protected.
        sister.age = 18;
        // Every protected and public field of sister is visible
        // I want to reduce visibility, since most protected fields
        // also have public getters and some setters which creates
        // too much visibility.
    }
}

So I guess it's only protected from outside of the family. Why is this and how can I have something hidden even from family members other then the direct parent and the child? To me it seems we're lacking an access member modifier. Something like family should actually be protected and protected should be hidden from all but the child and parent. I'm not asking anyone to rewrite Java, just noticing.

Madmenyo
  • 8,389
  • 7
  • 52
  • 99
  • Above code is not valid. – MC Emperor Jul 27 '15 at 14:10
  • @MCEmperor No it is not, but it shows the issue. – Madmenyo Jul 27 '15 at 14:11
  • What are you trying to achieve? Why is the brother making a new sister and why are both the brother and sister (subclasses of) parents? That doesn't make sense to me. – MC Emperor Jul 27 '15 at 14:19
  • @MCEmperor In my code a player object gets passed to a enemy object both inheriting entity which has a gazillion fields. When I just want to lookup players position and perhaps another view I get a list with the gazillion fields in front of me. No problem but I have been thought to keep access to fields small. Most fields are protected to just give access to the child and then most of those have getters and setters too. – Madmenyo Jul 27 '15 at 14:25
  • 1
    Are the classes in the same package? I've answered your question; you might want to take a look... – MC Emperor Jul 27 '15 at 14:32
  • @MCEmperor Yes, but if they are not in the same package I assume I cannot access age in either `Brother` or `Sister` class. – Madmenyo Jul 27 '15 at 14:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/84378/discussion-between-mc-emperor-and-menno-gouw). – MC Emperor Jul 27 '15 at 14:40
  • Because protected scope is broader than default access. – fps Jul 27 '15 at 14:54
  • @FedericoPeraltaSchaffner So I have to move a single Class to a different package in order to reduce visibility? That sounds hacky. Why can `protected` not have a less broader scope and introduce `family` for what protected is doing now? Not saying anyone should rewrite java but... I like to manage my visibility. – Madmenyo Jul 27 '15 at 14:56
  • 1
    Yes, they designed the language this way in the 90s... It's a design decision. Can't tell the authors' reasons, though, but it is this way. There doesn't exist a really protected scope i.e. a scope that makes members visible only to subclasses. – fps Jul 27 '15 at 15:28
  • @FedericoPeraltaSchaffner is this handled in the same way as in C# and C++ for example? – Madmenyo Jul 27 '15 at 15:40
  • public and private are the same, protected isn't (as you're learning now). Java has the default or package-private visibility that doesn't exist in C++, while C++ has the friend modifier to explicitly allow visibility between specific classes. Can't tell about C# scopes, it's ages since I don't even see a line of C# code... – fps Jul 27 '15 at 15:43
  • @FedericoPeraltaSchaffner Seems more logical in C++. But then again, I suck at C++ :) – Madmenyo Jul 27 '15 at 16:47

4 Answers4

3

That is because the classes Parent, Brother and Sister are in the same package. Members within the same package are always visible, except with the private modifier.

This code:

public class Sister {

    void someMethod() {
        Brother brother = new Brother();
        brother.age = 18;
    }
}

means you are working in the Sister class, and from there, you're trying to access the age member of the Brother class. Brother has nothing to do with Sister, except the fact that they accidentally extend the same parent class.

The only reason accessing the age member is valid, is because Brother and Sister are within the same package. Try to move either Brother or Sister to another package, and you'll see that the compiler starts complaining.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
  • Yes, but how can I reduce visibility of the fields belonging to brother in Sister? – Madmenyo Jul 27 '15 at 14:43
  • Either make them `private` or move the classes to different packages. But let's [continue this discussion in chat](http://chat.stackoverflow.com/rooms/84378/discussion-between-mc-emperor-and-menno-gouw). – MC Emperor Jul 27 '15 at 14:44
2

From the documentation you can see the following behaviors: public, protected, and private

public means everyone can view/alter it.

protected means that it its package and subclasses can view/alter it

private means its for the class only to view/alter it.

Also, check here for examples and easy to understand descriptions

Edit:

As a rule of thumb, think that a class extends another when "oneClass" is an "anotherClass", what you have written means that "brother" is a "parent", while it should be something as "brother" is a "person" and "sister" is a "person".

Right now, both are brother/sister and parent at the same time, leading to some confusion on what you are trying to perform

Edit 2:

class parent{
   private String age;
}
Bonatti
  • 2,778
  • 5
  • 23
  • 42
  • I have to ask you the same question as I asked Florian in the comments. "So it is impossible to have a field declared in the parent and hide it from child's other then themselves?" – Madmenyo Jul 27 '15 at 14:09
  • @MennoGouw check the edit2. Unless the Brother has an age atribute, your code should crash (but I dont remember the error name/code) – Bonatti Jul 27 '15 at 14:17
  • Let me test this. That would make things even more awkward to me. The IDE shows me I have access to sister.age but in the end it crashes on me :D. – Madmenyo Jul 27 '15 at 14:19
  • @MennoGouw before writting code, please reffer to documentation on what each command does/means. This WILL save you a LOT of trouble in the medium to long run. – Bonatti Jul 27 '15 at 14:31
2

If Brother and Sister are not in the same package as Parent, then the protected variable age of other instances is not visible. see Why can't my subclass access a protected variable of its superclass, when it's in a different package?

example:

package test.family.parent;

public class Parent {
    protected int age;
}


package test.family.child;
import test.family.parent.Parent;

public class Brother extends Parent {

public void test(){
        this.age = 1;
        Brother brother = new Brother();
        brother.age = 44; // OK
        Sister sister = new Sister();
        sister.age = 44;  // does not compile
    }
}

package test.family.child;
import test.family.parent.Parent;

public class Sister extends Parent {

    public void test(){
        this.age = 1;
        Brother brother = new Brother();
        brother.age = 44;  // does not compile
        Sister sister = new Sister();
        sister.age = 44;   // OK
    }
}

In this example, Sister can access age of itself and other instances, but not those of Brother

Community
  • 1
  • 1
user140547
  • 7,750
  • 3
  • 28
  • 80
  • But sister needs access to her age and brother needs access to her age. I just do not want to have Brother have access to her sisters age. It just seems to me that there is a access modifier missing that restricts access only directly from parent to child. And not give access to it's fields to both child's. – Madmenyo Jul 27 '15 at 14:16
  • I realize I gave a incorrect example because I wanted to simplify my question. I pass a brother object to sister by a method. So age is allready initialized for both. But I want to restrict visibility of `brother.age` in `Sister` class. – Madmenyo Jul 27 '15 at 14:32
  • It does not matter if you pass pass the `Brother` as a parameter or create it in the method. If you change the method in `Sister` to `public void test(Brother b)`, you can't access `Brother`'s age either. – user140547 Jul 27 '15 at 14:38
0

Modifiers are for classes. Your Brother is a parent, too, so it can access parent.age, since that field is protected. It doesn't matter if the actual object in question is this brother, another brother, a sister or any other parent.

Florian Schaetz
  • 10,454
  • 5
  • 32
  • 58
  • So it is impossible to have a field listed in the parent and hide it from child's other then themselves? – Madmenyo Jul 27 '15 at 13:53
  • You could make it package access and only put the children you want to see it in the same package, but that would be quite a hack... – Florian Schaetz Jul 27 '15 at 13:57
  • Yes indeed. I just wanted to have a couple of childs and they inherit a lot of fields. They should not be able to alter and in most cases get these fields. But when I want access to some they all get listed. I just wanted to reduce this list in a valid way. – Madmenyo Jul 27 '15 at 14:00
  • Since you cannot reduce visibility, I doubt this will really work, but perhaps someone around here has a great way that I simply haven't thought of yet... – Florian Schaetz Jul 27 '15 at 14:04
  • I'll wait a bit with accepting your answer then to lure a bit more people in it. Otherwise I accept it and post a new question directly related to my issue. Thanks for clarifying access modifiers to me, makes sense. Used them for years but just never had thought about them in that way. – Madmenyo Jul 27 '15 at 14:07