I was going through this question Is there a way to override class variables in Java?. The first comment with 122 upvotes was:
If you ever see a
protected static
, run.
Can anyone explain why is a protected static
frowned upon?
I was going through this question Is there a way to override class variables in Java?. The first comment with 122 upvotes was:
If you ever see a
protected static
, run.
Can anyone explain why is a protected static
frowned upon?
It's more a stylistic thing than a direct problem. It suggests that you haven't properly thought through what is going on with the class.
Think about what static
means:
This variable exists at class level, it does not exist separately for each instance and it does not have an independent existence in classes which extend me.
Think about what protected
means:
This variable can be seen by this class, classes in the same package and classes which extend me.
The two meanings are not exactly mutually exclusive but it is pretty close.
The only case I can see where you might use the two together is if you had an abstract class that was designed to be extended and the extending class could then modify the behavior using constants defined in the original. That sort of arrangement would most likely end up very messy though and indicates weakness in the design of the classes.
In most cases it would be better to have the constants as public since that just makes everything cleaner and allows the people sub-classing more flexibility. Quite apart from anything else in many cases composition is preferable to inheritance, while abstract classes force inheritance.
To see one example of how this could break things and to illustrate what I mean by the variable not having an independent existence try this example code:
public class Program {
public static void main (String[] args) throws java.lang.Exception {
System.out.println(new Test2().getTest());
Test.test = "changed";
System.out.println(new Test2().getTest());
}
}
abstract class Test {
protected static String test = "test";
}
class Test2 extends Test {
public String getTest() {
return test;
}
}
You will see the results:
test
changed
Try it yourself at: https://ideone.com/KM8u8O
The class Test2
is able to access the static member test
from Test
without needing to qualify the name - but it does not inherit or get its own copy. It is looking at the exact same object in memory.
It's frowned upon because it's contradictive.
Making a variable protected
implies it will be used within the package or it will be inherited within a subclass.
Making the variable static
makes it a member of the class, eliminating the intentions of inheriting it. This leaves only the intention of being used within a package, and we have package-private
for that (no modifier).
The only situation I could find this useful for is if you were declaring a class that should be used to launch the application (like JavaFX's Application#launch
, and only wanted to be able to launch from a subclass. If doing so, ensure the method is also final
to disallow hiding. But this is not "the norm", and was probably implemented to prevent adding more complexity by adding a new way to launch applications.
To see the access levels of each modifier, see this: The Java Tutorials - Controlling Access to Members of a Class
I don't see a particular reason why this should be frowned upon. There may always be alternatives to achieve the same behavior, and it will depend on the actual achitecture whether these alternatives are "better" than a protected static method or not. But one example where a protected static method would be reasonable, at least, could be the following:
(Edited to split into separate packages, to make the use of protected
clearer)
package a;
import java.util.List;
public abstract class BaseClass
{
public Integer compute(List<Integer> list)
{
return computeDefaultA(list)+computeDefaultB(list);
}
protected static Integer computeDefaultA(List<Integer> list)
{
return 12;
}
protected static Integer computeDefaultB(List<Integer> list)
{
return 34;
}
}
Derived from that:
package a.b;
import java.util.List;
import a.BaseClass;
abstract class ExtendingClassA extends BaseClass
{
@Override
public Integer compute(List<Integer> list)
{
return computeDefaultA(list)+computeOwnB(list);
}
private static Integer computeOwnB(List<Integer> list)
{
return 56;
}
}
Another derived class:
package a.b;
import java.util.List;
import a.BaseClass;
abstract class ExtendingClassB extends BaseClass
{
@Override
public Integer compute(List<Integer> list)
{
return computeOwnA(list)+computeDefaultB(list);
}
private static Integer computeOwnA(List<Integer> list)
{
return 78;
}
}
The protected static
modifier can certainly be justified here:
static
, because they do not depend on instance variables. They are not intended to be used directly as a polymorphic method, but rather are "utility" methods that offer default implementations that are part of a more complex computation, and serve as "building blocks" of the actual implementation.public
, because they are an implementation detail. And they can't be private
because they should be called by the extending classes. They also can't have "default" visibility, because then they will not be accessible for the extending classes in other packages.(EDIT: One could assume that the original comment only referred to fields, and not to methods - then, however, it was too general)
Static members are not inherited, and protected members are only visible to subclasses (and of course the containing class), so a protected static
has the same visibility as static
, suggesting a misunderstanding by the coder.
Actually there is nothing fundamentally wrong with protected static
. If you really want a static variable or method that is visible for the package and all subclasses of the declaring class then go ahead and make it protected static
.
Some people generally avoid to use protected
for various reasons and some people think non-final static
variables should be avoided by all means (I personally sympathize with the latter to some degree), so I guess the combination of protected
and static
must look bad^2 to those that belong to both groups.
Protected is used so that it can be used in subclasses. There is no logic in defining a protected static when using in the context of concrete classes as you can access the same variable is a static way.However the complier will give a warning to access the super class static variable in a static way.
Well, as most of the people have answered:
protected
means - 'package-private + visibility to subclasses - the property/behaviour is INHERITED'static
means - 'the opposite of instance - it is a CLASS property/behaviour, i.e it is NOT INHERITED'Therefore they are slightly contradictive and incompatible.
However, recently I came up to a use case where it might make sense to use these two together. Imagine that you want to create an abstract
class which is a parent for immutable types and it has a bunch of properties which are common to the subtypes. To implement immutability properly and keep readability one might decide to use the Builder pattern.
package X;
public abstract class AbstractType {
protected Object field1;
protected Object field2;
...
protected Object fieldN;
protected static abstract class BaseBuilder<T extends BaseBuilder<T>> {
private Object field1; // = some default value here
private Object field2; // = some default value here
...
private Object fieldN; // = some default value here
public T field1(Object value) { this.field1 = value; return self();}
public T field2(Object value) { this.field2 = value; return self();}
...
public T fieldN(Object value) { this.fieldN = value; return self();}
protected abstract T self(); // should always return this;
public abstract AbstractType build();
}
private AbstractType(BaseBuilder<?> b) {
this.field1 = b.field1;
this.field2 = b.field2;
...
this.fieldN = b.fieldN;
}
}
And why protected static
? Because I want a non-abstract subtype of AbstactType
which implements its own non-abstract Builder and is located outside package X
to be able to access and reuse the BaseBuilder
.
package Y;
public MyType1 extends AbstractType {
private Object filedN1;
public static class Builder extends AbstractType.BaseBuilder<Builder> {
private Object fieldN1; // = some default value here
public Builder fieldN1(Object value) { this.fieldN1 = value; return self();}
@Override protected Builder self() { return this; }
@Override public MyType build() { return new MyType(this); }
}
private MyType(Builder b) {
super(b);
this.fieldN1 = b.fieldN1;
}
}
Of course we can make the BaseBuilder
public but then we come to another contradictory statements:
So in both cases with protected static
and public
builder of an abstract class
we combine contradictory statements. It is a matter of personal preferences.
However, I still prefer the public
builder of an abstract class
because the protected static
to me feels more unnatural in a OOD and OOP world !
There is nothing wrong with having protected static
. One thing a lot of people are overlooking is that you may want to write test cases for static methods that you don't want to expose under normal circumstances. I've noticed this is particularly useful for writing tests for static method in utility classes.