Java Access Modifiers – Why Are Protected Members Accessible to Same Package Classes?

access-modifiersjavalanguage-designlanguage-features

From the official documentation

Modifier    Class   Package Subclass    World 
public      Y       Y       Y           Y 
protected   Y       Y       Y           N 
no modifier Y       Y       N           N 
private     Y       N       N           N 

The thing is, I can't remember having a use case where I needed to access protected members from a class within the same package.

What were the reasons behind this implementation?

Edit: To clarify, I'm looking for a specific use case where both a subclass and a class within the same package needs to access a protected field or method.

package some.package;
public class A {
 protected void protectedMethod(){
  // do something
 }
}

package another.package;
public class B extends A{
 public void someMethod(){
  // accessible because B is a subclass of A
  protectedMethod();
 }
} 

package some.package;
public class C {
 public void anotherMethod(){
  // accessible because C is in the same package as A
  protectedMehtod();
 }
}

Best Answer

looking for a specific use case where both a subclass and a class within the same package needs to access a protected field or method...

Well to me, such a use case is rather general than specific, and it stems from my preferences to:

  1. Start with as strict access modifier as possible, resorting to weaker one(s) only later as deemed necessary.
  2. Have unit tests reside in the same package as tested code.

From above, I can start designing for my objects with default access modifiers (I would start with private but that would complicate unit testing):

public class Example {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        void doSomething() {} // default access
    }
    static class Unit2 {
        void doSomething() {} // default access
    }

    static class UnitTest {
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

Side note in above snippet, Unit1, Unit2 and UnitTest are nested within Example for simplicity of presentation, but in a real project, I would likely have these classes in separate files (and UnitTest even in a separate directory).

Then, when a necessity arises, I would weaken access control from default to protected:

public class ExampleEvolved {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        protected void doSomething() {} // made protected
    }
    static class Unit2 {
        protected void doSomething() {} // made protected
    }

    static class UnitTest {
        // ---> no changes needed although UnitTest doesn't subclass
        // ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

You see, I can keep unit test code in ExampleEvolved unchanged due to protected methods being accessible from the same package, even though accessing object is not a sub-class.

Less changes needed => safer modification; after all I changed only access modifiers and I did not modify what methods Unit1.doSomething() and Unit2.doSomething() do, so it is only natural to expect unit test code to continue run without modifications.