Java: коли використовувати статичні методи


911

Мені цікаво, коли використовувати статичні методи? Скажіть, якщо у мене є клас з кількома геттерами та сеттерами, метод чи два, і я хочу, щоб ці методи були викликані лише на об'єкті екземпляра класу. Чи означає це, що я повинен використовувати статичний метод?

напр

Obj x = new Obj();
x.someMethod

або

Obj.someMethod

(це статичний шлях?)

Я досить розгублений!

Відповіді:


1458

Одне правило: запитайте себе: "Чи має сенс називати цей метод, навіть якщо жоден об'єкт ще не побудований?" Якщо так, то це безумовно має бути статичним.

Тож у класі у Carвас може бути метод:

double convertMpgToKpl(double mpg)

... що було б статично, тому що, можливо, хочеться знати, в що перетворюється 35mpg, навіть якщо ніхто ніколи не будував Car. Але цей метод (який встановлює ефективність одного конкретного Car):

void setMileage(double mpg)

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

(До речі, зворотне не завжди відповідає дійсності: іноді може бути метод, який включає два Carоб'єкти, і все-таки хочеться, щоб він був статичним. Наприклад:

Car theMoreEfficientOf( Car c1, Car c2 )

Хоча це може бути перетворене на нестатичну версію, деякі вважають, що оскільки не існує "привілейованого" вибору, який Carважливіший, ви не повинні змушувати абонента вибирати його Carяк об'єкт, до якого будете викликати метод на. Однак ця ситуація становить досить малу частину всіх статичних методів.)


325
Кілька хороших прикладів тут. Я хочу додати, однак, що "статичність" часто цінна, коли ти знаєш, що щось не зміниться в різних випадках. Якщо це так, я б дійсно вважав "Принцип єдиної відповідальності", який означає, що клас повинен мати одну відповідальність і, отже, лише одну причину для зміни. Я вважаю, що слід розглянути можливість переміщення функції "ConvertMpgToKpl (подвійний mpg)" та подібних методів до власного класу. Призначення автомобільного об'єкта - дозволити примірник автомобілів, а не забезпечити порівняння між ними. Вони повинні бути зовнішніми для класу.
Zack Jannsen

34
Я думаю, що я вважаю за краще метод Car#isMoreEfficientThan(Car). Він має перевагу в тому, який автомобіль ви повернете в краватці, не є довільним. За заголовком методу очевидно, що повертається краваткою.
Cruncher

5
Я також буду обережним щодо створення статичного методу, який використовує якийсь зовнішній ресурс (файлова система, база даних тощо). Цей тип статики може зробити жахливим тестування споживчих методів. Я особисто намагаюся зберегти статику в царині «корисності».
Сет М.

7
Фактично, його слід реалізувати як компаратор .
Dogweather

3
@ B1KMusic Звичайно. Що я маю на увазі під «який автомобіль повертається в краватці», це «справжні карти на закликаний автомобіль, а помилкові карти - на пройдений автомобіль». Це без двозначності.
Cruncher

538

Визначте статичні методи лише в наступних сценаріях:

  1. Якщо ви пишете корисні класи, і їх не слід змінювати.
  2. Якщо метод не використовує жодної змінної примірника.
  3. Якщо будь-яка операція не залежить від створення екземпляра.
  4. Якщо є якийсь код, який легко поділитися всіма методами екземпляра, витягніть цей код у статичний метод.
  5. Якщо ви впевнені, що визначення методу ніколи не буде змінено або перекрито. Оскільки статичні методи не можна перекрити.

45
хороші моменти, але вони є вимогами, якщо ви хочете зробити метод статичним, а не причини, щоб його зробити.
tetsuo

4
@Mohd про вимогу 5: Коли ви можете бути на 100% впевнені, що метод ніколи не буде змінений або відмінений? Чи не завжди є невідомі фактори, які ви не можете врахувати на момент написання статичного методу?
PixelPlex

8
"Класи утиліти" дуже важко міркувати. Погано в тому, що рано чи пізно все починає "виглядати" як утиліта (так, я маю на увазі той пакет "util", який роздутий, недоторканний і погано перевірений), і ваші тестові справи потребуватимуть додаткової роботи (знущатися над статичними утилітами - ТРУД). Віддайте перевагу предметам спочатку.
Серхіо

2
@Mohd ця відповідь саме те, що я шукаю. Я зіткнувся з безліччю проблем із використанням статичних методів у багатопотоковому читанні. Чи можете ви, будь ласка, уточнити пункти 2, 3 більше (з прикладом 100 великих пальців для вас)
Prakash Pandey

Я думаю, що "статичний клас" слід винайти, якщо ви збираєтесь використовувати статичні змінні та методи.
Роберт Роша

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

Я погоджуюся з продуктивністю та практичністю, але не з чистотою. Статичний метод може змінювати статичні члени класу (які можуть бути приватними). Це може бути корисно. Наприклад, у вас може бути такий метод, як "статичний синхронізований int allocateID () {return idNext ++;}". Насправді статичний метод може бути таким же чистим чи нечистим, як нестатичний метод з точки зору побічних ефектів.
Адам Гаун-Каїн

42

Прочитавши статті Місько, я вважаю, що статичні методи погані з точки зору тестування. Натомість вам слід мати фабрики (можливо, використовувати інструмент для введення залежності, як Guice ).

як я гарантую, що у мене є лише одне з чогось

тільки мати щось із чогось. Проблема "як я можу забезпечити, що у мене є лише одне із чогось" - це чітко проігноровано. Ви створюєте екземпляр лише одного ApplicationFactory в своєму головному, і, як результат, ви створюєте лише один екземпляр усіх ваших одиночних клавіш.

Основна проблема статичних методів - це процесуальний кодекс

Основна проблема статичних методів - це процесуальний кодекс. Я не маю уявлення, як правильно перевірити процедурний код. Тестування підрозділу передбачає, що я можу подати частину своєї програми ізольовано. Під час інстанції я передаю залежність з глузду / дружби, які замінюють реальні залежності. При процедурному програмуванні нічого не можна "підключити", оскільки об'єктів немає, код і дані є окремими.


20
Я не розумію частину про неможливість тестування процедурного коду. Чи не ви просто налаштували тестові випадки, які відображають правильний ввід для виправлення виводу, використовуючи статичний метод разом із класом як "одиницю"?
tjb

2
Ви можете зробити це для тестування цих функцій. Але, використовуючи ці статичні методи в інших класах, які ви хочете протестувати, я вважаю, що ви не можете їх підробити (макети / дружні) чи що-небудь, тому що ви не можете створити інстанціювання класу.
Альфред

4
@Alfred: Погляньте на PowerMock, який має змогу знущатися над статичними методами. Використовуючи PowerMock, існує декілька сценаріїв (якщо такі є), де ви знайдете залежності методів, які неможливо здійснити.
Карлес Сала

7
Ви можете пробувати тестування статики за допомогою PowerMock, однак незабаром ви побачите, що у вас залишилось місця в Пермґен (зробили це, отримала футболку), і її все ще неприємно. Якщо ви не знаєте (спираючись на принаймні десятиліття власного досвіду правдивих мов OO, не мігруючи з C), НЕ робіть цього. Серйозно, найгірший код, який я коли-небудь бачив, стався від використання статики вбудованим розробником, і в більшості випадків ми зациклювались на цьому назавжди, і додавання ще коду просто зафіксувало нас у немодифікованому моноліті ще сильніше. Вільна муфта: ні, перевіряється: ледве, змінюється: НІКОЛИ. Уникайте!
користувач1016765

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.");
     }
  }

найкраща відповідь насправді
Yahya

20

Статичні методи в java належать до класу (не його примірника). Вони не використовують змінних примірників і зазвичай беруть вхід з параметрів, виконують дії над ним, а потім повертають певний результат. Методи екземплярів пов'язані з об'єктами і, як випливає з назви, можуть використовувати змінні екземпляра.


12

Ні, статичні методи не пов'язані з екземпляром; вони належать до класу. Статичні методи - ваш другий приклад; Екземплярні методи є першими.


1
Ви повинні використовувати статичні методи, якщо не потрібні маніпуляції зі станом об'єкта.
MastAvalons

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


10

Статичні методи не пов'язані з екземпляром, тому вони не можуть отримати доступ до жодних нестатичних полів у класі.

Ви використовуєте статичний метод, якщо метод не використовує жодних полів (або лише статичних полів) класу.

Якщо використовуються будь-які нестатичні поля класу, ви повинні використовувати нестатичний метод.


1
Чітка, коротка та проста відповідь.
Josi

8

Статичні методи повинні бути викликані в Класі, методи екземплярів - в екземплярах класу. Але що це означає насправді? Ось корисний приклад:

Клас автомобіля може мати метод примірника, який називається Accelerate (). Прискорити автомобіль можна лише в тому випадку, якщо машина насправді існує (була побудована) і тому це був би метод примірника.

Автомобільний клас може також мати метод підрахунку, який називається GetCarCount (). Це поверне загальну кількість створених (або сконструйованих) автомобілів. Якщо б не було побудовано жодних машин, цей метод повертав би 0, але його все одно можна було б викликати, і тому він повинен був статичним методом.


6

Насправді ми використовуємо статичні властивості та методи в класі, коли ми хочемо використати якусь частину нашої програми, яка повинна існувати там, поки наша програма не працює. І ми знаємо, що для маніпулювання статичними властивостями нам потрібні статичні методи, оскільки вони не є частиною змінної примірника. І без статичних методів маніпулювати статичними властивостями забирає багато часу.


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

5

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


29
Це не дає жодних обґрунтувань для розробки програми.
adamjmarkham

4

Статичний: Obj.someMethod

Використовуйте, staticколи ви хочете забезпечити доступ на рівні класу до методу, тобто там, де метод повинен бути викликаний без екземпляра класу.


4

Статичні методи не потрібно викликати на об'єкті, і саме тоді ви його використовуєте. Приклад: ваш Main () є статичним, і ви не створюєте об'єкт для його виклику.


1
Так! Подивіться, куди я прийшов, гуглюючи питання щодо Java Noobie! Це маленький світ :-)
Діпак

1
@Deepak маленький світ справді :)
Vaishak Suresh

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, які можна викликати без створення об’єкта класу. Це належить до класу.

Ми використовуємо статичний метод, коли нам не потрібно викликати метод, використовуючи екземпляр.


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. Методи класу не можуть отримати доступ до змінних екземплярів або методів екземпляра безпосередньо - вони повинні використовувати посилання на об'єкт. Крім того, методи класу не можуть використовувати це ключове слово, оскільки для цього немає жодного примірника.

Чи не можемо ми отримати доступ до статичних полів звичайними методами? Тоді це A common use for static methods is to access static fields.не аргумент.
розбір

2

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

  1. Для корисних або допоміжних методів, які не потребують стану об'єкта. Оскільки немає необхідності звертатися до змінних екземплярів, наявність статичних методів виключає необхідність викликати абонент об'єкт просто для виклику методу.
  2. Для стану, яким поділяються всі екземпляри класу, як лічильник. Усі екземпляри повинні мати однаковий стан. Методи, які просто використовують цей стан, повинні бути статичними.

1

У затемненні ви можете увімкнути попередження, яке допоможе вам виявити потенційні статичні методи. (Над виділеною лінією - ще одна, яку я забув виділити)

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


0

Щоразу, коли ви не хочете створити об'єкт для виклику методу у своєму коді, просто оголосіть цей метод статичним. Оскільки статичний метод не потребує виклику екземпляра, але улов тут не всі статичні методи викликаються JVM автоматично. Цією привілею користується лише головний () "загальнодоступний статичний недійсний основний [String ... args]" метод в java, оскільки під час виконання це метод Public Signature "статичний" недійсний 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 Цей статичний метод потрібно викликати явно Цей статичний метод потрібно викликати явно Цей статичний метод потрібно викликати явно

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.