Когда НЕ использовать статическое ключевое слово в Java?

Когда считается, что плохая практика использует статическое ключевое слово в Java для сигнатур методов? Если метод выполняет функцию, основанную на некоторых аргументах, и не требует доступа к полям, которые не являются статическими, то не всегда ли вы хотите, чтобы эти типы методов были статическими?

Ответ 1

Одна из причин, почему вы не хотите, чтобы она была статичной, - это позволить ее переопределить в подклассе. Другими словами, поведение может не зависеть от данных внутри объекта, а от точного типа объекта. Например, у вас может быть общий тип коллекции с атрибутом isReadOnly, который возвратит false в всегда изменяемые коллекции, true в неизменяемых коллекциях и будет зависеть от переменных экземпляра в других.

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

Ответ 2

Два из самых больших зол, с которыми вы когда-либо столкнетесь в широкомасштабных приложениях Java:

  • Статические методы, кроме тех, которые являются чистыми функциями *
  • Переменные статические поля

Они разрушают модульность, расширяемость и проверяемость вашего кода до такой степени, что я понимаю, что не могу надеяться убедить вас в этом ограниченном времени и пространстве.

* "Чистая функция" - это любой метод, который не изменяет никакого состояния и результат которого зависит только от параметров, предоставленных ему. Так, например, любая функция, которая выполняет ввод/вывод (прямо или косвенно), не является чистой функцией, но Math.sqrt(), конечно, есть.

Больше blahblah о чистых функциях (self-link) и почему вы хотите придерживаться их.

Я настоятельно рекомендую вам одобрить стиль программирования "зависимость", возможно, поддерживаемый каркасом, таким как Spring или Guice (отказ от ответственности: я являюсь соавтором последнего). Если вы сделаете это правильно, вам по существу не понадобятся измененные статические состояния или нечистые статические методы.

Ответ 3

В общем, я предпочитаю методы экземпляра по следующим причинам:

  • статические методы жестко проверяют, потому что их нельзя заменить,
  • статические методы более процедурны.

На мой взгляд, статические методы в порядке для классов полезности (например, StringUtils), но я предпочитаю избегать их использования как можно больше.

Ответ 4

То, что вы говорите, похоже на истину, но что происходит, когда вы хотите переопределить поведение этого метода в производном классе? Если он статичен, вы не можете этого сделать.

В качестве примера рассмотрим следующий класс типа DAO:

class CustomerDAO {
    public void CreateCustomer( Connection dbConn, Customer c ) {
       // Some implementation, created a prepared statement, inserts the customer record.
    }

    public Customer GetCustomerByID( Connection dbConn, int customerId ) {
       // Implementation
    }
}

Теперь ни один из этих методов не требует какого-либо "состояния". Все, что им нужно, передается как параметры. Поэтому они МОГУТ быть легко статичными. Теперь возникает потребность в поддержке другой базы данных (скажем, Oracle)

Поскольку эти методы не являются статическими, вы можете просто создать новый класс DAO:

class OracleCustomerDAO : CustomerDAO {
    public void CreateCustomer( Connection dbConn, Customer c ) {
        // Oracle specific implementation here.
    }

    public Customer GetCustomerByID( Connection dbConn, int customerId ) {
        // Oracle specific implementation here.
    }
}

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

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

Ответ 5

Статические методы обычно пишутся для двух целей. Первая цель - иметь какой-то глобальный метод полезности, аналогичный той функциональности, которая находится в java.util.Collections. Эти статические методы обычно безвредны. Вторая цель - контролировать создание экземпляра объекта и ограничивать доступ к ресурсам (например, соединениям с базой данных) с помощью различных шаблонов проектирования, таких как singletons и заводы. Они могут, если они плохо реализованы, приводят к проблемам.

Для меня есть два недостатка в использовании статических методов:

  • Они делают код менее модульным и сложнее тестировать/расширять. Большинство ответов уже адресовано этому, поэтому я больше не буду вдаваться в это.
  • Статические методы, как правило, приводят к некоторой форме глобального состояния, что часто является причиной коварных ошибок. Это может произойти в плохо написанном коде, который написан для второй цели, описанной выше. Позвольте мне уточнить.

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

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

Чтобы избежать этих проблем, разработчикам следует избегать хранения любого состояния с помощью статических методов и переменных. Вместо этого они должны создавать чистые API, которые позволяют пользователям управлять и изолировать состояние по мере необходимости. BerkeleyDB является хорошим примером здесь, инкапсулируя состояние через Environment вместо статических вызовов.

Ответ 6

Это правильно. В самом деле, вам нужно судить, что в противном случае может быть разумным дизайном (иметь некоторые функции, не связанные с классом) в термины Java. Вот почему вы видите все классы, такие как FredsSwingUtils и YetAnotherIOUtils.

Ответ 7

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

Ответ 8

Дополнительная досада о статических методах: нет простого способа передать ссылку на такую ​​функцию, не создавая вокруг нее класс-оболочку. Например. - что-то вроде:

FunctorInterface f = new FunctorInterface() { public int calc( int x) { return MyClass.calc( x); } };

Я ненавижу этот вид java make-work. Может быть, более поздняя версия java получит делегатов или аналогичный механизм указателя/процедурного типа функции?

Небольшая проблема, но еще одна вещь, которая не нравится в отношении бесплатных статических функций, er, методов.

Ответ 9

Два вопроса здесь 1) Статический метод, который создает объекты, которые загружаются в память при первом обращении? Разве это (оставшийся в памяти) недостаток? 2) Одним из преимуществ использования Java является его функция сбора мусора - arent мы игнорируем это, когда мы используем статические методы?