Почему мы не должны использовать защищенную статику в java
Я проходил через этот вопрос есть ли способ переопределить переменные класса в Java? Первый комментарий с 36 upvotes был:
Если вы когда-нибудь видели
protected static
запустите.
может кто-нибудь объяснить, почему это protected static
неодобрением?
8 ответов:
это скорее стилистическая вещь, чем прямая проблема. Это говорит о том, что вы не правильно продумали, что происходит с классом.
думать о том, что
static
означает:эта переменная существует на уровне класса, оно не существует отдельно для каждого экземпляра и он не имеет независимого существования в классах, которые расширяют меня.
думать о том, что
protected
означает:этот переменная может быть видна этим классом, классы в одном пакете и классы, которые расширяют меня.
эти два значения не совсем взаимоисключающие, но это довольно близко.
единственный случай, когда я вижу, где вы можете использовать их вместе, - это если у вас есть абстрактный класс, который был разработан для расширения, и расширяющий класс может затем изменить поведение, используя константы, определенные в оригинале. Даже тогда это очень слабая причина, хотя как вы все равно почти наверняка будете лучше иметь константы как публичные. Это просто делает все чище и позволяет людям подклассифицировать больше гибкости.
чтобы развернуть и объяснить первый пункт-попробуйте этот пример кода:
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; } }
вы увидите результаты:
test changed
попробуйте сами по адресу:https://ideone.com/KM8u8O
класс
Test2
может получить доступ к статическому членуtest
СTest
без необходимости чтобы квалифицировать имя-но оно не наследует или не получает свою собственную копию. Он смотрит на ту же самую переменную.
это нахмурилось, потому что это противоречит.
создание переменной
protected
подразумевает, что он будет использоваться в пакете или это будет наследуется внутри подкласса.создание переменной
static
делает его членом класса, устранение намерения наследовать его. Это оставляет только намерение быть использованным в пакете и мыpackage-private
для этого (нет модификатор.)единственная ситуация, в которой я мог бы найти это полезным, - это если вы объявляете класс, который должен использоваться для запуска приложения (например, JavaFX
Application#launch
, и только хотел, чтобы иметь возможность запускать из подкласса. Если это так, убедитесь, что метод такжеfinal
запретить прячась. Но это не "норма", и, вероятно, было реализовано, чтобы предотвратить добавление большей сложности, добавив новый способ запуска приложений.чтобы увидеть уровни доступа для каждого модификатора см. Следующее:учебники Java-управление доступом к членам класса
Я не вижу особой причины, почему это должно быть нахмурено. Всегда могут быть альтернативы для достижения того же поведения, и это будет зависеть от фактической архитектуры, являются ли эти альтернативы "лучше", чем защищенный статический метод или нет. Но один пример, где защищенный статический метод был бы разумным, по крайней мере, может быть следующим:
(отредактировано для разделения на отдельные пакеты, чтобы использовать
protected
понятнее)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; } }
производные из этого:
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; } }
еще один производный класс:
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
модификатор, безусловно, может быть оправдан здесь:
- методы могут быть
static
, потому что они не зависят от переменных экземпляра. Они не предназначены для непосредственного использования в качестве полиморфного метода, а скорее являются "полезными" методами, которые предлагают default реализации которые являются частью более сложных вычислений и служат "строительными блоками" фактического реализация.- методы не должны быть
public
, потому что они являются деталями реализации. И они не могут бытьprivate
потому что они должны быть вызваны расширения классов. Они также не могут иметь видимость "по умолчанию", потому что тогда они не будут доступны для расширяющихся классов в других пакетах.(EDIT: можно предположить, что исходный комментарий относится только к поля, а не способы - тогда, однако, это было слишком общее)
статические члены не наследуются, а защищенные члены видны только подклассам (и, конечно же, содержащему классу), поэтому a
protected static
имеет ту же видимость, какstatic
, предполагая недоразумение со стороны кодера.
Protected используется для того, чтобы его можно было использовать в подклассах. Нет никакой логики в определении защищенной статики при использовании в контексте конкретных классов, поскольку вы можете получить доступ к той же переменной статическим способом.Однако компилятор выдаст предупреждение получить доступ к супер статической переменной класса в статический способ.
на самом деле нет ничего принципиально плохого с
protected static
. Если вы действительно хотите статическую переменную или метод, который виден для пакета и всех подклассов объявляющего класса, то идите вперед и сделайте этоprotected static
.некоторые люди вообще избегают использовать
protected
по разным причинам и некоторые люди думают, что не окончательныйstatic
переменных следует избегать всеми средствами (я лично сочувствую последнему в какой-то степени), поэтому я предполагаю комбинациюprotected
иstatic
надо смотреть плохо^2 к тем, которые принадлежат к обеим группам.
нет ничего плохого в том, что
protected static
. Одна вещь, которую многие люди упускают из виду, заключается в том, что вы можете написать тестовые случаи для статических методов, которые вы не хотите раскрывать при обычных обстоятельствах. Я заметил это особенно полезно для написания тестов для статических методов в классах.
Ну, как большинство людей ответили:
protected
означает - 'package-private + visibility to subclasses-свойство / поведение наследуется'static
означает - 'противоположность instance - это свойство/поведение класса, т. е. оно не наследуется'поэтому они немного противоречивы и несовместимы.
однако, недавно я подошел к случаю использования, где возможно, имеет смысл использовать эти два вместе. Представьте, что вы хотите создать
abstract
класс, который является родительским для неизменяемые типы и имеет кучу свойств, которые являются общими для всех подтипов. Для реализации неизменность правильно и сохранить читабельности можно было бы решить использовать Строитель узор.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; } }
и почему
protected static
? Потому что я хочу не абстрактный подтип изAbstactType
который реализует свой собственный неабстрактный конструктор и находится снаружиpackage X
чтобы иметь возможность доступа и повторного использования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; } }
конечно, мы можем сделать
BaseBuilder
публика но тут мы приходим к другому противоречивому утверждению:
- у нас есть неинстантируемый класс (абстрактный)
- мы предоставляем общественный Строитель для него
так что в обоих случаях с
protected static
иpublic
строитель Анabstract class
мы объединяем противоречивые утверждения. Это вопрос личных предпочтений.однако, я все еще предпочитаю
public
Строитель вabstract class
потому чтоprotected static
мне кажется более неестественным в мире УД и ООП !