Почему мы не должны использовать защищенный static в java

Я обсуждал этот вопрос Есть ли способ переопределить переменные класса в Java? Первый комментарий с 36 upvotes был:

Если вы когда-либо видели protected static, запустите.

Может ли кто-нибудь объяснить, почему protected static нахмурился?

Ответ 1

Это скорее стилистическая вещь, чем прямая проблема. Это предполагает, что вы не правильно продумали, что происходит с классом.

Подумайте, что означает 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 без необходимости квалифицировать имя - но он не наследует и не получает свою собственную копию. Он смотрит на ту же самую переменную.

Ответ 2

Он нахмурился, потому что это противоречиво.

Создание переменной protected подразумевает, что она будет использоваться внутри пакета или будет наследоваться внутри подкласса.

Создание переменной static делает ее членом класса, устраняет намерения наследовать ее. Это оставляет только намерение быть использованным в пакете, и у нас есть package-private для этого (без модификатора).

Единственная ситуация, в которой я мог бы найти это полезное значение, - это объявление класса, который должен использоваться для запуска приложения (например, JavaFX Application#launch), и только хотел, чтобы он мог запускаться из подкласса. убедитесь, что метод также final запрещает скрытие. Но это не "норма", и, вероятно, было реализовано, чтобы не добавлять дополнительную сложность добавление нового способа запуска приложений.

Чтобы увидеть уровни доступа каждого модификатора, см. это: Учебники по Java - контроль доступа к членам класса

Ответ 3

Я не вижу особой причины, почему это следует недооценивать. Всегда могут быть альтернативы для достижения такого же поведения, и это будет зависеть от фактической архитектуры того, являются ли эти альтернативы "лучше", чем защищенный статический метод или нет. Но один пример, когда защищенный статический метод был бы разумным, по крайней мере, мог бы быть следующим:

(Отредактировано для разделения на отдельные пакеты, чтобы использовать 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;
    }
}

Производится из этого:

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;
    }
}

Модификатор protected static, безусловно, может быть оправдан здесь:

  • Методы могут быть static, потому что они не зависят от переменных экземпляра. Они не предназначены для непосредственного использования в качестве полиморфного метода, а скорее являются "полезными" методами, которые предлагают реализации по умолчанию, которые являются частью более сложного вычисления и служат "строительными блоками" фактической реализации.
  • Методы не должны быть public, поскольку они являются деталями реализации. И они не могут быть private, потому что они должны быть вызваны расширяющимися классами. Они также не могут иметь видимость по умолчанию, потому что тогда они не будут доступны для расширяющих классов в других пакетах.

(EDIT: можно предположить, что исходный комментарий относится только к полям, а не к методам - ​​тогда, однако, он был слишком общим)

Ответ 4

Статические элементы не наследуются, а защищенные члены видны только для подклассов (и, конечно, для класса), поэтому protected static имеет ту же видимость, что и static, что указывает на непонимание кодера.

Ответ 5

Защищен используется, чтобы его можно было использовать в подклассах. Нет никакой логики в определении защищенного статического элемента при использовании в контексте конкретных классов, так как вы можете получить доступ к одной и той же переменной, является статическим способом. Однако разработчик будет давать предупреждение для доступа к статической переменной суперкласса статическим способом.

Ответ 6

На самом деле в protected static нет ничего принципиально неправильного. Если вам действительно нужна статическая переменная или метод, которые видны для пакета и всех подклассов объявляющего класса, тогда сделайте это protected static.

Некоторые люди обычно избегают использовать protected по разным причинам, и некоторые люди считают, что не конечные переменные static следует избегать всеми способами (лично я сочувствую последнему до некоторой степени), поэтому я предполагаю, что сочетание protected и static должны выглядеть плохо ^ 2 тем, которые принадлежат обеим группам.

Ответ 7

Нет ничего плохого в наличии protected static. Одна вещь, которую многие игнорируют, заключается в том, что вы можете написать тестовые примеры для статических методов, которые вы не хотите раскрывать при нормальных обстоятельствах. Я заметил, что это особенно полезно для написания тестов для статического метода в служебных классах.