Stranger Things About Java: The protected Modifier
This deep dive into Java's protected modifier will cover why and how to use the protected access specifier when coding.
Join the DZone community and get the full member experience.Join For Free
protected modifier is a rarely-used access specifier. It is applicable to variables, methods and constructors, but not to Java types (classes, interfaces, enumerations, annotations, and records), unless they are nested in other types. In this post, we will avoid talking about nested types and we will focus on this modifier referring mainly to class members (variables and methods) to make the discussion simpler. In particular, we will make some important observations regarding
protected, which is often used without the necessary prerequisite knowledge. In addition, we will also digress into discussing the Singleton pattern to add extensibility.
All Java programmers know how to use the
private modifiers, as they are used daily in programming. The
protected modifier, on the other hand, is used much less frequently, and when used it is not uncommon for it to be used inappropriately, sometimes because its correct definition is ignored.
When applied to a member of a class, the
protected modifier defines the highest degree of accessibility after that defined by the
public modifier. In fact, a
protected member will be accessible within the same package (via the dot operator), but will also be inherited in all subclasses of the class in which it is defined, even if they don't belong to the same package.
If we're talking about member visibility, using the
protected modifier or using no modifier is the same thing. In fact, we can call package scope (or default scope) when we do not use any modifier to declare a class member that will be accessible in all types defined in the same package.
For example, consider the
ProtectedClass class, which declares a
protected variable and a
Furthermore, let’s consider the following
ProtectedClassSamePackage class belonging to the same package:
This class will compile without a problem, even if it explicitly uses the members declared as
protected in the superclass via the dot operator as if they were declared
Instead, if we try to use
protected members in the same way in a class belonging to a different package like the following:
we will get the following compile-time errors:
just because it is in a different package.
We would have obtained the same result even if the members of the class
ProtectedClass had declared them with package scope, that is, we had not used any modifier.
However, declaring a
protected member is important when, in addition to wanting to limit the scope to the package it belongs to, we also want it to be inherited in subclasses even if it's external to the package. So, using
protected makes sense only when we want to use inheritance. In fact, the subclasses inherit members declared
protected in the superclass, even if these subclasses belong to packages that are different from the package to which the superclass belongs.
For example, the following subclass of the
belongs to the same package as the superclass, and can be compiled without errors.
But the same goes for a subclass that belongs to a different package like the following:
The Stranger Thing
Unfortunately, another class that is in a package other than
com.claudiodesio.blog.staj, will not be able to access the
protected members inherited from the
ProtectedClass superclass, because the scope of these methods is limited to the package where they were declared. For example, compiling the following class:
will result in an error whose description leaves no doubt:
StrangerThingsAboutProtectedTest is in the same package as the
ProtectedSubclassOtherPackage class, it cannot invoke its
protected method, because the scope of that method is limited to the
com.claudiodesio.blog.staj package where it was declared.
Clearly, if the
StrangerThingsAboutProtectedTest class belonged to the
com.claudiodesio.blog.staj package and correctly imported the
ProtectedSubclassOtherPackage class, the compilation would be successful.
In this case, to fix the problem we can override the protected method,
protectedMethod, in the
ProtectedSubclassOtherPackage subclass, for example, in the following way:
StrangerThingsAboutProtectedTest class can compile and run correctly. In fact, the
protectedMethod method is redefined by the
ProtectedSubclassOtherPackage class, belonging to the
com.claudiodesio.blog.staj.other package where the
StrangerThingsAboutProtectedTest class is also located.
Note that for the overriding rules, the
protectedMethod method in the
ProtectedSubclassOtherPackage subclass could also be declared
And What About Variables?
The same problem also arises with protected variables. In fact, if the method of the
StrangerThingsAboutProtectedTest class tried to access the
we would get the following error:
Also in this case, in order to compile correctly, we could rewrite the variable in the subclass:
An absolutely inelegant solution. On the other hand, as we will see in the following sections, the
protected modifier can be very useful when applied to methods, constructors, and, in some cases, to constants. It is much less useful when applied to variables.
By declaring a protected constructor, we can make a class instantiable only within a certain package, but at the same time extendable with subclasses that also belong to different packages. An interesting example is the one related to the famous Singleton design pattern. A typical implementation in Java involves the declaration of a private constructor. Actually, in the famous book that first formalized this pattern, Design Patterns: Elements of Reusable Object-Oriented Software, it was proposed to declare the constructor as
protected, to allow the extension of the Singleton class (see Figure 1).
Figure 1: The code example written in C ++ proposed in the Design Patterns book.
The proposed example was written in C ++ (Java did not exist at the time), where the
protected modifier is defined in a simpler and more natural way. In fact, since the concept of a 'package' does not exist in C++, the use of the
protected modifier in C++ guarantees a private scope and support for inheritance.
To support the inheritance of a Singleton class in Java, on the other hand, declaring the constructor as
protected is not enough. It is also necessary to include this class within a dedicated package, that is, it does not contain other classes. If not, the other classes could instantiate the singleton class violating the pattern philosophy. Having said this, the following example represents an extensible singleton:
Provided that the
com.claudiodesio.blog.staj.singleton package does not contain any other classes.
But if the use of
protected is primarily intended for methods and constructors, declaring a protected variable is unnecessary or even wrong most of the time.
In fact, a common mistake among newbies is to think that in order to use a certain variable in a subclass it is necessary to declare it as
protected, when it is already sufficient to have a mutator (set) and an accessor (get) methods inherited in the subclasses. Furthermore, declaring an instance variable as
protected means making it directly accessible to all classes belonging to the same package, and, except in rare cases, this is not the level of encapsulation desired. Therefore, if we consider the
Book subclass, we can safely set and get the id variable. In fact, even though we didn't inherit it, we still inherited the
getId methods. For example, we could implement the
Book subclass in the following way:
Note that we used the
setId method within the constructor. So, it is not necessary to declare the variable
protected in the
Item superclass, and thus break the encapsulation contract.
In this article, we have explored a basic topic, such as the
protected modifier, and in particular its relationship with inheritance. This modifier can be useful when applied to methods and constructors, but much less for encapsulated variables. Since it is one of those topics that are learned in the early stages when learning the language, and since it is a rarely-used modifier, some programmers overlook the subtleties of its definition, and in some cases, it is used inappropriately.
This article is based on some sections of chapters 5 and 6 of my book Java for Aliens.
Published at DZone with permission of Claudio De Sio Cesari. See the original article here.
Opinions expressed by DZone contributors are their own.