Подтвердить что ты не робот

В Java существует ли какой-либо недостаток статических методов в классе?

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

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

Я знаю, что вопрос был несколько открытым и неопределенным, поэтому я извиняюсь за это. Мое намерение в вопросе было в контексте, в основном, "вспомогательных" методов. Классы полезности (с частными CTOR, поэтому они не могут быть созданы) как обладатели статических методов, которые мы уже делаем. Мой вопрос здесь был больше в строю этих небольших методов, которые ПОМОЧЬЮ из основного класса API.

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

Ответ 3

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

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

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

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

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

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

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

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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

 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 
  }

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

Ответ 6

Disadvantage -> Static

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

Ответ 7

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

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

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

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

Ответ 8

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

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, mean, variance и т.д. И хранить ее где-то. Где? В состоянии объекта. Если бы это было действительно одноразовое, вы могли бы сделать его статичным, но, конечно же, вы обнаружите, что хотите вычислить среднее значение двух разных вещей, а затем это ужасно приятно, если вы можете просто создать экземпляр объекта несколько раз.

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

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

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

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

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

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

Ответ 9

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

Ответ 10

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

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

Ответ 11

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

Ответ 12

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

Ответ 13

В целом:

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

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

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

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

В частности:

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

Ответ 14

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

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

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

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

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