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();
}
}
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:
- Start with as strict access modifier as possible, resorting to weaker one(s) only later as deemed necessary.
- 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.
0
I’d say this has two parts:
- The default, “package”, access is useful in wide range of cases, because classes are not always good unit of encapsulation. Various composite objects where some object acts as collection of other objects, but the items must not be publicly modifiable, because there are some invariants across the whole collection, so the collection needs to have elevated access to the items. C++ has friends, Java has package access.
- Now the “package” access scope is basically independent of the “subclass” (protected) scope. So you’d need additional access specifiers for package only, subclasses only and package and subclasses. The “package” scope is more restricted as set of classes in a package is usually definite while a subclass may appear anywhere. So to keep things simple, Java simply includes the package access in the protected access and does not have extra specifier for subclasses-but-not-package. Though you should almost always think of
protected
as exactly that.
4
IMHO, this was a bad design decision in Java.
Just speculating, but I think they wanted the access levels to be in a strict progression: private – “package” – protected – public. They didn’t want to have a hierarchy, where some fields would be available to the package but not subclasses, some available to subclasses but not the package, and some both.
Still, in my humble opinion they should have gone the other way: Said that protected is visible to the class and subclasses only, and that package is visible to the class, subclasses, and the package.
I often have data in a class that needs to be accessible to subclasses, but not to the rest of the package. I’m hard pressed to think of a case where the reverse was true. I’ve had a few rare occasions where I’ve had a bundle of interrelated classes that need to share data but which should keep that data safe from outside the bundle. So okay, put them in a package, etc. But I’ve never had a case where I want the package to share data, but I want to keep it from sub-classes. Okay, I can imagine the situation coming up. I suppose if this package is part of a library that might be extended by classes I know nothing about, for much the same reasons I would make data in a class private. But it’s way more common to want to make data available only to the class and its children.
There are lots of things that I keep private between me and my kids and we don’t share with the neighbors. There’s very little that I keep private between me and the neighbors and don’t share with my kids. 🙂
A good example that immediately comes to mind is utility classes that are used a lot in the package but you don’t want public access (behind-the-scenes-image-loading-from-disk, handle-creation/destruction classes, etc.) instead of making everything [Java’s equivalent friend access modifier or idiom
in C++
] of every other class everything is automatically available.
1
The use cases for the protected/package access modifier are similar to the ones for friend access modifiers in C++.
One use case is when implementing the Memento pattern.
The memento object needs to access the internal state of an object, to hold it, in order to serve as a checkpoint for undo operations.
Declaring the class in the same package is one of the possible ways to achieve the Memento pattern, since Java has no “friend” access modifier.
3
symmetry?
It’s rare to need such access, which is why default access is so rarely used. But sometimes frameworks want it for generated code, where wrapper classes are placed in the same package that interact with your classes directly, going to members instead of accessors for performance reasons.. Think GWT.
1
Java’s encapsulation hierarchy is well defined:
Class -> Package -> Inheritance
“Protected” is just a weaker form of privacy than package-default as decided on by the Java designers. Access to package-default items is restricted to a subset of the entities that are allowed to access protected items.
It makes a lot of sense from a mathematical- and implementation point of view to have your sets of entities that are allowed to access things to be nested. (You couldn’t nest your package-access set inside your protected-access set because classes are allowed to inherit from other packages).
It makes sense from a conceptual point of view to have something in java.util to be “friendlier” with another class in the package than something in com.example.foo.bar that is subclassing it. In the former case the classes are likely to be written by the same author, or at least coders from the same organisation.
1