Java: когда использовать статические методы

911

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

например

Obj x = new Obj();
x.someMethod

или

Obj.someMethod

(это статический способ?)

Я довольно смущен!

KP65
источник

Ответы:

1458

Одно эмпирическое правило: спросите себя: «Есть ли смысл вызывать этот метод, даже если объект еще не был построен?» Если это так, то он обязательно должен быть статичным.

Так что в классе у Carвас может быть метод:

double convertMpgToKpl(double mpg)

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

void setMileage(double mpg)

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

(Между прочим, обратное не всегда верно: иногда вы можете иметь метод, который включает два Carобъекта, и все же хотите, чтобы он был статическим. Например:

Car theMoreEfficientOf( Car c1, Car c2 )

Хотя это может быть преобразовано в нестатическую версию, некоторые утверждают, что, поскольку нет «привилегированного» выбора, который Carболее важен, вы не должны заставлять вызывающего абонента выбирать его Carв качестве объекта, который вы вызываете. метод на. Эта ситуация объясняет довольно небольшую долю всех статических методов.)

не-только-йети
источник
325
Несколько хороших примеров здесь. Однако я бы добавил, что «статический» часто полезен, когда вы знаете, что что-то не меняется в разных случаях. Если это так, я бы действительно рассмотрел «Принцип единой ответственности», который подразумевает, что класс должен иметь одну ответственность и, следовательно, только одну причину для изменения. Я считаю, что следует рассмотреть возможность перемещения функции «ConvertMpgToKpl (double mpg)» и аналогичных методов в их собственный класс. Цель объекта автомобиля состоит в том, чтобы разрешить создание экземпляров автомобилей, а не обеспечить сравнение между ними. Они должны быть внешними по отношению к классу.
Зак Яннсен
34
Я думаю, что я предпочел бы метод Car#isMoreEfficientThan(Car). Преимущество в том, что автомобиль, который вы возвращаете в галстуке, не является произвольным. По названию метода очевидно, что возвращается в связи.
Cruncher
5
Я также хотел бы быть осторожным при создании статического метода, использующего некоторый внешний ресурс (файловую систему, базу данных и т. Д.), Этот тип статического кода может сделать ужасным тестирование потребляющих методов. Я лично стараюсь держать статику в сфере «полезности».
Сет М.
7
На самом деле, это должно быть реализовано как компаратор .
Dogweather
3
@ B1KMusic Конечно. То, что я имею в виду, «какая машина возвращается в галстуке» - это «истинные карты для вызванной машины и ложные карты для пропущенной машины». Это без двусмысленности.
Cruncher
538

Определите статические методы только в следующих сценариях:

  1. Если вы пишете служебные классы, и они не должны быть изменены.
  2. Если метод не использует какую-либо переменную экземпляра.
  3. Если какая-либо операция не зависит от создания экземпляра.
  4. Если есть некоторый код, который может быть легко использован всеми методами экземпляра, извлеките этот код в статический метод.
  5. Если вы уверены, что определение метода никогда не будет изменено или переопределено. Так как статические методы не могут быть переопределены.
Мохд
источник
46
Хорошие моменты, но это требования, если вы хотите сделать метод статичным, а не причины для его создания.
tetsuo
4
@Mohd о требовании 5: когда вы можете быть на 100% уверены, что метод никогда не будет изменен или переопределен? Не всегда ли существуют неизвестные факторы, которые вы не можете принять во внимание в момент написания статического метода?
PixelPlex
8
«Утилиты-классы» очень трудно рассуждать, плохо то, что рано или поздно все начинает «выглядеть как» утилита (да, я имею в виду тот «утилитарный» пакет, который раздутый, неприкасаемый и плохо протестированный), и ваши тесты будут нуждаться в дополнительной работе (издеваться над статическими утилитами - СЛОЖНО). Предпочитаю объекты в первую очередь.
Серхио
2
@ Мохд, этот ответ - именно то, что я ищу. Я столкнулся с множеством проблем при использовании статических методов в многопоточности. Можете ли вы уточнить пункты 2, 3 еще (например, 100 больших пальцев для вас)
Пракаш Пандей
Я думаю, что «статический класс» должен быть изобретен, если вы собираетесь использовать статические переменные и методы.
Роберт Роча
182

Есть несколько веских причин использовать статические методы:

  • Производительность : если вы хотите, чтобы какой-то код выполнялся, и не хотите создавать для этого дополнительный объект, вставьте его в статический метод. JVM также может оптимизировать статические методы (я думаю, что я когда-то читал Джеймса Гослинга, заявляющего, что вам не нужны пользовательские инструкции в JVM, поскольку статические методы будут такими же быстрыми, но не смогут найти источник - таким образом это может быть полностью ложным). Да, это микрооптимизация, и, вероятно, она не нужна. И мы, программисты, никогда не делаем ненужных вещей только потому, что они крутые, верно?

  • Практичность : вместо вызова new Util().method(arg), вызова Util.method(arg)или method(arg)со статическим импортом. Проще, короче.

  • Добавление методов : вы действительно хотели, чтобы класс String имел removeSpecialChars()метод экземпляра, но его там нет (и не должно быть, поскольку специальные символы вашего проекта могут отличаться от других проектов), и вы не можете добавить его (поскольку Java несколько вменяемый), поэтому вы создаете служебный класс и вызываете removeSpecialChars(s)вместо s.removeSpecialChars(). Сладкий.

  • Чистота : принимая некоторые меры предосторожности, ваш статический метод будет чистой функцией , то есть от него зависят только параметры. Данные в, данные в. Это легче читать и отлаживать, так как вам не нужно беспокоиться об особенностях наследования. Вы можете сделать это и с методами экземпляра, но компилятор поможет вам немного больше со статическими методами (не допуская ссылки на атрибуты экземпляра, переопределяющие методы и т. Д.).

Вам также нужно будет создать статический метод, если вы хотите создать синглтон, но ... не надо. Я имею в виду, подумай дважды.

Теперь, что более важно, почему вы не хотите создавать статический метод? В основном, полиморфизм уходит в окно . Вы не сможете ни переопределить метод, ни объявить его в интерфейсе (до Java 8) . Это требует много гибкости от вашего дизайна. Кроме того, если вам нужно состояние , у вас будет много ошибок параллелизма и / или узких мест, если вы не будете осторожны.

Тэцуо
источник
1
Здесь перечислено много веских причин, когда статика может быть полезной. Еще я могу вспомнить, что написание модульных тестов для таких методов просто-напросто
nilesh
@ Tetsuo Спасибо! Ваше объяснение очень ясное, а приведенные причины очень логичны и имеют много смысла.
Денис М.
3
И мы, программисты, никогда не делаем ненужных вещей только потому, что они крутые, верно? +1
Скарамуш
Тем не менее, статический метод становится полностью именованной функцией stackoverflow.com/questions/155609/…
Ivanzinho
Я согласен с Производительностью и Практичностью, но не Чистотой. Статический метод может изменять статические члены класса (которые могут быть закрытыми). Это может быть полезно. Например, у вас может быть метод типа «static synchronized int allocateID () {return idNext ++;}». Фактически, статический метод может быть таким же чистым или нечистым, как и нестатический метод с точки зрения побочных эффектов.
Адам Гавн-Каин
42

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

как мне убедиться, что у меня есть только один

У меня есть только один предмет Что-то вроде проблемы «как мне убедиться, что у меня есть только один предмет?» приятно обойти стороной. Вы создаете экземпляр только одной ApplicationFactory в своей основной базе данных, и в результате вы создаете только один экземпляр всех своих синглетонов.

Основная проблема со статическими методами - это процедурный код

Основная проблема со статическими методами - это процедурный код. Я понятия не имею, как провести модульное тестирование процедурного кода. Модульное тестирование предполагает, что я могу создать экземпляр своего приложения изолированно. Во время создания экземпляра я связываю зависимости с помощью mocks / friendlies, которые заменяют реальные зависимости. При процедурном программировании нечего «связывать», поскольку нет объектов, код и данные разделены.

Альфред
источник
20
Я не понимаю часть о невозможности модульного тестирования процедурного кода. Разве вы не устанавливаете тестовые случаи, которые отображают корректный ввод в корректный вывод, используя статический метод вместе с классом в качестве «единицы»?
tjb
2
Вы можете сделать это, чтобы проверить эти функции. Но при использовании этих статических методов в других классах, которые вы хотите протестировать, я считаю, что вы не можете подделать их (издевательства / дружественные отношения) или что-то еще, потому что вы не можете создать экземпляр класса.
Альфред
4
@ Альфред: Пожалуйста, взгляните на PowerMock, который имеет возможность издеваться над статическими методами. При использовании PowerMock существует несколько сценариев, если таковые имеются, где вы найдете зависимости методов, которые нельзя смоделировать.
Карлес Сала
7
Вы можете выполнить модульный тест статики с помощью PowerMock, однако вскоре вы обнаружите, что у вас закончилось пространство Пермгена (сделано, получил футболку), и оно все еще противно. Если вы НЕ ЗНАЕТЕ (основываясь, по крайней мере, на десятилетии своего собственного опыта работы с настоящими ОО-языками, не переходя с C), НЕ ДЕЛАЙТЕ ЭТОГО. Серьезно, худший код, который я когда-либо видел, исходил от использования статики разработчиком встроенных программ, и в большинстве случаев мы застряли с ним навсегда, и добавление большего количества кода просто заперло нас в неизменяемом монолите еще теснее. Слабая связь: нет, проверяемая: едва ли, модифицируемая: НИКОГДА. Избегайте!
user1016765
14
Я могу понять сложность тестирования статических методов, которые зависят от статического состояния. Но когда вы тестируете статические методы без сохранения состояния, такие как Math.abs()или Arrays.sort()даже методы, в которые можно передать все зависимости , я не понимаю, как это могло бы помешать модульному тестированию. Я бы сказал, что простое эмпирическое правило таково: если у вас есть какая-либо причина издеваться над процедурной логикой, не используйте статический метод. У меня никогда не было причин издеваться Arrays.sort()или Math.abs().
Энди
36

staticМетод является одним типа способа , который не требует какого - либо объекта , который будет инициализирован для того , чтобы назвать. Вы заметили static, используется в mainфункции в Java? Выполнение программы начинается оттуда без создания объекта.

Рассмотрим следующий пример:

 class Languages 
 {
     public static void main(String[] args) 
     {
         display();
     }

     static void display() 
     {
         System.out.println("Java is my favorite programming language.");
     }
  }
Zishan
источник
лучший ответ на самом деле
Яхья
20

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

Кевин Сильвестр
источник
12

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

duffymo
источник
1
Вы должны использовать статические методы, если вам не нужны манипуляции с состоянием объекта.
Маставалон
11

Если вы применяете статическое ключевое слово с любым методом, оно называется статическим методом.

  1. Статический метод принадлежит классу, а не объекту класса.
  2. Статический метод вызывается без необходимости создания экземпляра класса.
  3. Статический метод может получить доступ к статическому члену данных и может изменить его значение.
  4. Доступ к статическому методу можно получить, просто используя имя статического имени точки класса. , , пример: Student9.change ();
  5. Если вы хотите использовать нестатические поля класса, вы должны использовать нестатический метод.

// Программа изменения общего свойства всех объектов (статическое поле).

class Student9{  
 int rollno;  
 String name;  
 static String college = "ITS";  

 static void change(){  
 college = "BBDIT";  
 }  

 Student9(int r, String n){  
 rollno = r;  
 name = n;  
 }  

 void display (){System.out.println(rollno+" "+name+" "+college);}  

public static void main(String args[]){  
Student9.change();  

Student9 s1 = new Student9 (111,"Indian");  
Student9 s2 = new Student9 (222,"American");  
Student9 s3 = new Student9 (333,"China");  

s1.display();  
s2.display();  
s3.display();  
}  }

O / P: 111 индийских BBDIT 222 американских BBDIT 333 китайских BBDIT

IndianProgrammer1234
источник
10

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

Вы бы использовали статический метод, если метод не использует какие-либо поля (или только статические поля) класса.

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

Карстен
источник
1
Четкий, короткий и простой ответ.
Джози
8

Статические методы должны вызываться в классе, методы экземпляра должны вызываться в экземплярах класса. Но что это значит на самом деле? Вот полезный пример:

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

У автомобильного класса также может быть метод count, называемый GetCarCount (). Это вернет общее количество созданных (или построенных) автомобилей. Если не было построено ни одного автомобиля, этот метод вернул бы 0, но его все равно можно было бы вызвать, и поэтому он должен был бы быть статическим методом.

Чарли Селигман
источник
6

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

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

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

Jamey
источник
29
Это не дает никакого обоснования для разработки программы.
adamjmarkham
4

Статическая: Obj.someMethod

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

Finbarr
источник
4

Статические методы не нужно вызывать для объекта, и именно тогда вы его используете. Пример: ваш Main () является статическим, и вы не создаете объект для его вызова.

Вайшак Суреш
источник
1
Ура! Посмотрите, куда я пришел, когда гуглил вопросы о нуби Java! Это маленький мир :-)
Дипак
1
@Deepak маленький мир действительно :)
Вайшак Суреш
4

Статические методы и переменные являются контролируемой версией глобальных функций и переменных в Java. В каких методах можно получить доступ как classname.methodName()или classInstanceName.methodName(), то есть к статическим методам и переменным можно получить доступ, используя имя класса, а также экземпляры класса.

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

Манджу Ядав
источник
3

Статические методы могут быть использованы, если

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

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

    1. new ABCClass(double farenheit).convertFarenheitToCelcium() 
    2. ABCClass.convertFarenheitToCelcium(double farenheit)

    первый создает новый след класса для каждого вызова метода, Performance, Practical . Примерами являются класс StringUtils библиотеки Math и Apache-Commons:

    Math.random()
    Math.sqrt(double)
    Math.min(int, int)
    StringUtils.isEmpty(String)
    StringUtils.isBlank(String)
  • Один хочет использовать в качестве простой функции. Входные данные передаются явно, и получение данных результата в качестве возвращаемого значения. Наследование, объектное воплощение не входит в картину. Краткий, Читаемый .

ПРИМЕЧАНИЕ . Немногие люди выступают против тестируемости статических методов, но статические методы тоже можно тестировать! С помощью jMockit можно высмеивать статические методы. Тестируемость . Пример ниже:

new MockUp<ClassName>() {
    @Mock
    public int doSomething(Input input1, Input input2){
        return returnValue;
    }
};
Амит Канерия
источник
3

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

Мы используем статический метод, когда нам не нужно вызывать метод с использованием instance.

rashedcs
источник
2

Мне интересно, когда использовать статические методы?

  1. Обычное использование staticметодов для доступа к staticполям.
  2. Но вы можете иметь staticметоды, не ссылаясь на staticпеременные. Вспомогательные методы без ссылки на staticпеременную можно найти в некоторых классах Java, таких как java.lang.Math.

    public static int min(int a, int b) {
        return (a <= b) ? a : b;
    }
  3. Другой вариант использования, который я могу представить в сочетании с synchronizedметодом, - реализация блокировки на уровне класса в многопоточной среде.

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

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

Страница документации Oracle содержит более подробную информацию.

Разрешены не все комбинации переменных и методов экземпляра и класса:

  1. Методы экземпляра могут напрямую обращаться к переменным экземпляра и методам экземпляра.
  2. Методы экземпляра могут напрямую обращаться к переменным класса и методам класса.
  3. Методы класса могут обращаться к переменным класса и методам класса напрямую.
  4. Методы класса не могут обращаться к переменным экземпляра или методам экземпляра напрямую - они должны использовать ссылку на объект. Кроме того, методы класса не могут использовать ключевое слово this, так как для этого нет экземпляра.
Равиндра Бабу
источник
Разве мы не можем получить доступ к статическим полям обычными методами? Тогда это A common use for static methods is to access static fields.не аргумент.
парсер
2

Статический метод имеет две основные цели:

  1. Для служебных или вспомогательных методов, которые не требуют какого-либо состояния объекта. Поскольку нет необходимости обращаться к переменным экземпляра, наличие статических методов устраняет необходимость для вызывающей стороны создавать экземпляр объекта просто для вызова метода.
  2. Для состояния, которое используется всеми экземплярами класса, например счетчик. Все экземпляры должны находиться в одном и том же состоянии. Методы, которые просто используют это состояние, также должны быть статическими.
hemanto
источник
1

В eclipse вы можете включить предупреждение, которое поможет вам обнаружить потенциальные статические методы. (Над выделенной строкой есть еще одна, которую я забыл выделить)

настройка затмения

ave4496
источник
0

Всякий раз, когда вы не хотите создавать объект для вызова метода в вашем коде, просто объявите этот метод как статический. Поскольку статическому методу не требуется вызывать экземпляр, но здесь есть загвоздка, не все статические методы вызываются JVM автоматически. Эта привилегия используется только в методе main () "public static void main [String ... args]" в java, поскольку во время выполнения это метод Signature public "static" void main [], который JVM ищет в качестве точки входа в начать выполнение кода.

Пример:

public class Demo
{
   public static void main(String... args) 
   {
      Demo d = new Demo();

      System.out.println("This static method is executed by JVM");

     //Now to call the static method Displ() you can use the below methods:
           Displ(); //By method name itself    
      Demo.Displ(); //By using class name//Recommended
         d.Displ(); //By using instance //Not recommended
   }

   public static void Displ()
   {
      System.out.println("This static method needs to be called explicitly");
   }
} 

Вывод: - Этот статический метод выполняется JVM. Этот статический метод должен вызываться явно. Этот статический метод должен вызываться явно. Этот статический метод должен вызываться явно.

Amrit
источник