В Java, там какой-либо недостаток к статическим методам для класса?

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

(отредактированный для дальнейших разъяснений)

Я знаю, что вопрос был несколько открыт законченный и неопределенный, таким образом, я приношу извинения за это. Мое намерение в выяснении было в контексте главным образом методов "помощника". Служебные классы (с частным CTORs, таким образом, они нельзя инстанцировать) как держатели для статических методов мы уже делаем. Мой вопрос здесь больше был в гармонии этих небольших методов, которые ВЫРУЧАЮТ основной класс API.

У меня могло бы быть 4 или 5 основных API/методов экземпляра на классе, которые делают реальную работу, но в ходе выполнения, таким образом, они совместно используют некоторую общую функциональность, которая могла бы только работать над входными параметрами к методу API и не внутренним состоянием. ЭТО секции кода, которые я обычно вытаскиваю в их собственные вспомогательные методы, и если они не должны получать доступ к состоянию класса, сделайте их статичными.

Мой вопрос был таким образом, это - по сути плохая идея, и если так, почему? (Или почему нет?)

36
задан Michael Campbell 18 March 2010 в 20:55
поделиться

13 ответов

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

28
ответ дан 27 November 2019 в 05:25
поделиться

В общем:

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

ArrayList badList = new ArrayList();  //bad
List goodList = new ArrayList();  //good

Вам должно быть разрешено менять реализации, особенно для имитации и тестирования. В этом отношении инъекция зависимостей Spring довольно хороша. Просто внедрите реализацию из Spring и bingo, у вас есть в значительной степени "статический" (ну, одноэлементный) метод ...

Теперь те типы API, которые являются чисто "полезными" по назначению (например, Apache Commons Lang), являются здесь исключение, потому что я считаю, что большинство (если не все) реализаций статичны. В этой ситуации, каковы шансы, что вы когда-либо захотите заменить Apache Commons на другой API?

В частности:

Как бы вы элегантно справились со «статичностью» своей реализации, когда вы ориентируетесь, скажем, на развертывание Websphere против Tomcat? Я уверен, что будет случай (без каламбура), когда ваша реализация будет отличаться между этими двумя ... и полагаться на статический метод в одной из этих конкретных реализаций может быть опасно ...

{{1 }}
0
ответ дан 27 November 2019 в 05:25
поделиться

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

0
ответ дан 27 November 2019 в 05:25
поделиться

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

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

1
ответ дан 27 November 2019 в 05:25
поделиться

Для вызова статических методов вам не нужно создавать объекты класса. Метод доступен сразу.

Предполагая, что класс уже загружен. В противном случае придется немного подождать. : -)

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

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

2
ответ дан 27 November 2019 в 05:25
поделиться

Вероятно, преимущество в производительности незначительно. Используйте статические методы для всего, что не зависит от состояния. Это проясняет код, поскольку при вызове статического метода сразу видно, что состояние экземпляра не задействовано.

17
ответ дан 27 November 2019 в 05:25
поделиться

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

1
ответ дан 27 November 2019 в 05:25
поделиться

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

public class Sorting {
  public static void quiksort(int [] array) {}
  public static void heapsort(int[] array) { }
}

Сказав это, есть много людей, которые пишут какой-то код и настаивают на том, чтобы у них был какой-то особый разовый код, но позже обнаруживают, что это не так. Например, вы хотите рассчитать статистику по переменной. Итак, вы пишете:

public class Stats {
  public static void printStats(float[] data) { }
}

Первый элемент плохого дизайна здесь состоит в том, что программист намеревается просто распечатать результаты, а не использовать их в общих чертах. Встраивание ввода-вывода в вычисления ужасно для повторного использования. Однако следующая проблема заключается в том, что эта процедура общего назначения должна вычислять max, min, среднее значение, дисперсию и т. Д. И где-то сохранять их. Где? В состоянии объекта. Если бы это было действительно разовое, вы могли бы сделать его статическим, но, конечно, вы обнаружите, что хотите вычислить среднее значение двух разных вещей, и тогда будет ужасно приятно, если вы можете просто создать экземпляр объекта несколько раз. .

public class Stats {
  private double min,max,mean,var;
  public void compute(float data[]) { ... }
  public double getMin() { return min; }
  public double
}

Коленный рефлекс против статики часто является реакцией программистов на глупость выполнения такого рода вещей статически, поскольку легче просто сказать «никогда не делай этого», чем объяснить, какие случаи допустимы, а какие - глупо.

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

Что касается производительности, то наибольшее увеличение производительности при переключении с обычного метода на самом деле заключается в том, чтобы избежать динамической полиморфной проверки, которая используется по умолчанию в java и которая в C ++ задается вручную с помощью virtual.

Когда я пытался в последний раз, было 3: 1 преимущество вызова метода final над обычным методом, но не было заметно для вызова статических функций над final.

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

4
ответ дан 27 November 2019 в 05:25
поделиться

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

1
ответ дан 27 November 2019 в 05:25
поделиться

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

Полезные классы, имеющие статические методы, - хорошая идея.

Классы обслуживания, несущие бизнес-логику, во многих случаях могут не иметь состояния. Первоначально я всегда добавлял в них статические методы, но затем, когда я лучше познакомился с фреймворком Spring (и немного больше читал), я понял, что эти методы становятся не тестируемыми как независимая единица, поскольку вы не можете легко внедрить имитационные сервисы в этот класс. Например. Статический метод, вызывающий другой статический метод в другом классе, JUnit test не может сократить этот путь путем внедрения фиктивной реализации во время выполнения.

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

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

7
ответ дан 27 November 2019 в 05:25
поделиться

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

Приятно обозначать функции как функции вместо того, чтобы они выглядели как методы - (а статические "методы" - это функции, а не методы - это фактически по определению).

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

Если статический метод просто принимает собственные значения, то вам, вероятно, не хватает нескольких классов; вам также следует свести к минимуму передачу собственных переменных или библиотечных объектов (например, коллекций) - вместо этого их следует содержать в классах с бизнес-логикой.

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

0
ответ дан 27 November 2019 в 05:25
поделиться

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

Если у вас все еще есть сомнения (может ли ваша реализация измениться в будущем или нет), вы всегда можете использовать частный экземпляр внизу с фактической реализацией:

 class StringUtil {
     private static StringUtil impl = new DefaultStringUtil();

     public static String nullOrValue( String s ) {
          return impl.doNullOrValue();
     }
     ... rest omitted 
  }

Если по «какой-то» причине, вы необходимо изменить предлагаемый класс реализации:

  class StringUtil {
     private static StringUtil impl = new ExoticStringUtil();

     public static String nullOrValue( String s ) {
          return impl.doNullOrValue(s);
     }
     ... rest omitted 
  }

Но в некоторых случаях может быть чрезмерным.

3
ответ дан 27 November 2019 в 05:25
поделиться

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

  1. Как уже отмечали другие, статические методы нельзя высмеивать в модульных тестах. Если класс зависит, скажем, от DatabaseUtils.createConnection(), то этот зависимый класс и любые классы, которые зависят от него, будет практически невозможно протестировать без наличия базы данных или какого-либо флага "тестирования" в DatabaseUtils. В последнем случае, похоже, у вас есть две реализации интерфейса DatabaseConnectionProvider - см. следующий пункт.

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

    boolean oldFlag = MyUtils.getFlag();
    MyUtils.someMethod();
    MyUtils.setFlag( oldFlag );
    

    Одним из примеров общей библиотеки, столкнувшейся с этой проблемой, является Apache Commons Lang: см. StringUtilsBean и т.д.

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

  4. Если у вас есть статические методы, которые ссылаются на статические переменные, то они остаются в течение всего времени работы загрузчика класса и никогда не собираются в мусор. Если они накапливают информацию (например, в кэше) и вы не будете осторожны, то в вашем приложении могут возникнуть "утечки памяти". Если вместо этого вы используете методы экземпляра, то объекты, как правило, живут меньше, и поэтому через некоторое время собирают мусор. Конечно, вы все еще можете столкнуться с утечкой памяти при использовании методов экземпляра! Но это меньшая проблема.

Надеюсь, это поможет!

25
ответ дан 27 November 2019 в 05:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: