The difference between default and protected access in Java

Posted by Monik, 02 June 2016.
Programming Java

I feel that this topic is a bit under explained, so I attempt here to explain it once and for good.

The four public, protected, default, private access modes are most often presented as a list, where the visibility decreases when you move from public towards private. But this I find very confusing, as in some corner cases this model simply does not work. I want to present an alternative understanding here.

Table of contents

Introduction

The public and private are easy to understand. The first one means “visible to everyone”, and the second “visible only to me”. No big deal here.

Then comes the protected. Oh, that is like something in between, visible only to me and all my subclasses. Okay clear, right.

And finally, the default access. What I had in my mind until now, was that it is just like protected but without the visibility for subclasses, only classes from the same package. Kind of special case.

The problem

Well and here is a bit of inconsistency, because when we spoke about visibility to subclasses, we meant that this:

package a;
public class A {
    protected int something;
}
package b;
public class B extends A {
    void check(){
        int h = this.something;
    }
}

but definitely we did not mean this:

package a;
public class A {
    protected int something;
}
package b;
public class B extends A {
    void check(){
        A anotherObject = new A();
        int h = anotherObject.something; //COMPILATION ERROR
    }
}

even though B extends A.

On the other hand, the last example would compile if both classes were in the same package:

package a;
public class A {
    protected int something;
}
package a;
public class B extends A {
    void check(){
        A anotherObject = new A();
        int h = anotherObject.something; //compiles!
    }
}

It would also compile if both classes were in the same package and B didn’t extend A.

package a;
public class A {
    protected int something;
}
package a;
public class B {
    void check(){
        A anotherObject = new A();
        int h = anotherObject.something; //compiles!
    }
}

As long as the classes are in the same package, it would also compile if something had the default access (with or without inheritance).

package a;
public class A {
    int something;
}
package a;
public class B {
    void check(){
        A anotherObject = new A();
        int h = anotherObject.something; //compiles!
    }
}

Conclusion

So instead of presenting the 4 access modes as a list, I would rather present it as a matrix:

visible to self visible to same package visible to all packages
visible to self private default
visible to subclasses protected
visible to everyone public

Highly illogical, isn’t it? But I bet that is why it caused me so much confusion when I tried to shrink it to a list.

The solution

One way to remember that is that protected and default are both between public and private but in a different way. As you move from public to private, the default access decreases the package access only, restricting it to classes only from the same package (not subpackages btw). Next, protected builds on top of default, allowing access in children even if they are not in the same package:

        less access            less access
public -------------> default---------------> private
                        |
                        |
                        | more access
                       \|/
                        V
                     protected

Be aware that “visible to subclasses” does not mean that every object has access to protected fields and methods of every concrete object that is of its supertype. It has access only to its own inherited fields and methods. May be obvious, but after hours of reading OCA study guide and doing mock exams that’s what was no longer clear to me..

You can also ignore the whole thing with granting package access and just say, that for any class the following holds:

inside every other class in the same package everything that is not marked as private is seen from inside the first class as if it was marked public.

I just made the above up and I think it does make sense.. at least now :)


Comments


Comments: