Що робить "статичне" ключове слово в класі?


444

Щоб бути конкретним, я намагався цей код:

package hello;

public class Hello {

    Clock clock = new Clock();

    public static void main(String args[]) {
        clock.sayTime();
    }
}

Але це дало помилку

Неможливо отримати доступ до нестатичного поля в основному статичного методу

Тому я змінив декларацію clockна це:

static Clock clock = new Clock();

І це спрацювало. Що означає ставити це ключове слово перед декларацією? Що саме це зробить та / або обмежить з точки зору того, що можна зробити для цього об’єкта?


Ще раз пам’ятайте, що є один екземпляр статики на клас на CLASSLOADER.
Javamann

Відповіді:


633

static члени належать до класу замість конкретного екземпляра.

Це означає, що існує лише один екземпляр staticполя [1], навіть якщо ви створюєте мільйон екземплярів класу або не створюєте жодного. Їм поділяться всі примірники.

Оскільки staticметоди також не належать до конкретного примірника, вони не можуть посилатися на членів екземпляра. У наведеному прикладі mainне відомо, до якого примірника Helloкласу (а отже, до якого примірника Clockкласу) він повинен посилатися. staticчлени можуть посилатися лише на staticчленів. Члени інстанції можуть, звичайно, отримувати доступ до staticчленів.

Бічна примітка: Звичайно, staticчлени можуть отримати доступ до членів екземплярів через посилання на об'єкт .

Приклад:

public class Example {
    private static boolean staticField;
    private boolean instanceField;
    public static void main(String[] args) {
        // a static method can access static fields
        staticField = true;

        // a static method can access instance fields through an object reference
        Example instance = new Example();
        instance.instanceField = true;
    }

[1]: Залежно від характеристик часу виконання, він може бути один на ClassLoader або AppDomain або потік, але це знаходиться поза точкою.


5
У .NET ви також можете змінити цю поведінку, використовуючи атрибут [ThreadStatic] - який робить статичний локальний для конкретних потоків.
TheSoftwareJedi

4
Я знаю, що це старий пост, але для початківців, як я, це може бути корисним. stackoverflow.com/questions/7026507 / ...
user3526905

Ви не зможете отримати доступ до instance.instanceField, оскільки це приватний var? Або це дійсно, тому що ви створили об'єкт всередині власного класу? Для мене це звучить як рекурсивний кошмар, але я новачок на Java.
Метт Корбі

Якщо на статичний член класу посилаються дві різні нитки, то скільки примірників цього статичного члена є? Я відчуваю, що це 2, але якщо ви хочете той самий екземпляр у нитках, тоді потрібно використовувати мінливе ключове слово. Це правильно?
Дан

..і чи зберігається значення, якщо не залишилося жодного примірника класу?
mckenzm

130

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

Тож якби ви робили "новий привіт" в будь-якому місці свого коду: A - у першому сценарії (перед зміною, не використовуючи "статичний"), він створював би новий годинник кожного разу, коли "новий привіт" буде викликано, але B- у другому сценарії (після зміни, використовуючи "статичний"), кожен "новий привіт" екземпляр все одно поділиться та використає первісну та ту саму "тактову" посилання, створену спочатку.

Якщо б вам не знадобився "годинник" десь поза основним, це спрацювало б так само:

package hello;
public class Hello
{
    public static void main(String args[])
    {
      Clock clock=new Clock();
      clock.sayTime();    
    }
}

Це більш звичний спосіб зробити це. main()Процедура повинна бути самодостатньою.
Джейсон S

1
У другому випадку вона створювала б новий екземпляр Clock кожного разу, коли основний метод викликається, правда?
Клацніть Upvote

2
По-друге, годинник статичний, він створив би його лише один раз. У моєму прикладі, коли годинник знаходиться в межах основного, тоді так, він створював би його новий щоразу, коли викликається головний. Але зазвичай основний викликається лише один раз при запуску програми, і коли він закінчується, все є безкоштовним.
Пол Томблін

Я не можу зрозуміти, як можливо зробити новий годинник основним методом? як ви кажете, це створювало б його нове щоразу, коли викликається головний, але існує лише один основний метод. як цей основний метод може стосуватися різних годинників? Трохи важко зрозуміти, як можливо зробити новий екземпляр годин в основному і використовувати його метод sayTime (), але неможливо зробити екземпляр з основного і використовувати sayTime (). як все безкоштовно, коли main викликається один раз? @PaulTomblin
ShakibaZar

@ user5621266 Я використовував mainметод лише тому, що це зробив ОП. Якщо натомість це був публічний метод, який викликався з іншого місця, а клас Hello інстанціювався не один раз, то він міг створити екземпляр Clock для кожного примірника Hello, якщо тільки clockвін не був статичним.
Пол Томблін

97

У staticключовому слові означає , що що - то (поле, метод або вкладений клас) відносяться до типу , а не якомусь - якого конкретного екземпляру типу. Так, наприклад, один дзвінок Math.sin(...)без жодного примірника Mathкласу, і справді ви не можете створити екземпляр Mathкласу.

Для отримання додаткової інформації див відповідний біт навчального посібника Java Oracle .


Sidenote

На жаль, Java дозволяє отримувати доступ до статичних членів так, ніби вони були членами екземпляра, наприклад

// Bad code!
Thread.currentThread().sleep(5000);
someOtherThread.sleep(5000);

Це робить його виглядати так , як ніби sleepце метод примірника, але це насправді статичний метод - це завжди робить поточний сон нитки. Краще практика, щоб це було зрозуміло у викликовому коді:

// Clearer
Thread.sleep(5000);

1
Інший приклад: System.out.println () виглядає як метод класу, але насправді це метод екземпляра. Оскільки Out є екземпляром PrintStream у класові System.
Цзяхуй Чжан

@LeslieCheung: Ні, це не схоже на метод класу для мене, як System.outі мені не подобається ім'я типу.
Джон Скіт

42

staticКлючове слово в Java означає , що змінна або функція поділяється між усіма примірниками цього класу , як він ставиться до типу , а не власними фактичні об'єкти.

Отже, якщо у вас є змінна: private static int i = 0;і ви збільшуєте її ( i++) в одному екземплярі, зміна буде відображена у всіх екземплярах. iтепер буде 1 у всіх випадках.

Статичні методи можна використовувати без інстанції об'єкта.


4
«Shared між усіма примірниками» дає неправильне враження, IMO - це говорить про те , що ви робите потреба мати екземпляр об'єкта.
Джон Скіт

1
(Тоді як насправді не потрібно бути жодних екземплярів, оскільки статичне поле тощо належить до типу .)
Jon Skeet

@Jon Skeet статична належить до типу, а не об'єкта? Чи можете ви розповісти детальніше? Тип типу даних: int, double, ...?
truongnm

@truongnm: Введіть як у класі, який оголошує змінну / метод.
Джон Скіт

26

Основне використання статичних членів ...

public class Hello
{
    // value / method
    public static String staticValue;
    public String nonStaticValue;
}

class A
{
    Hello hello = new Hello();
    hello.staticValue = "abc";
    hello.nonStaticValue = "xyz";
}

class B
{
    Hello hello2 = new Hello(); // here staticValue = "abc"
    hello2.staticValue; // will have value of "abc"
    hello2.nonStaticValue; // will have value of null
}

Ось так ви можете мати значення, що діляться всім членам класу, не надсилаючи примірник класу Привіт іншому класу. І щоб статично вам не потрібно створювати екземпляр класу.

Hello hello = new Hello();
hello.staticValue = "abc";

Ви можете просто викликати статичні значення або методи за назвою класу:

Hello.staticValue = "abc";

22

Статичний означає, що вам не потрібно створювати екземпляр класу, щоб використовувати методи або змінні, пов'язані з класом. У своєму прикладі ви можете зателефонувати:

Hello.main(new String[]()) //main(...) is declared as a static function in the Hello class

безпосередньо замість:

Hello h = new Hello();
h.main(new String[]()); //main(...) is a non-static function linked with the "h" variable

Зсередини статичним методом (який належить до класу) ви не можете отримати доступ до будь-яких членів, які не є статичними, оскільки їх значення залежать від вашої інстанції класу. Нестатичний об'єкт Clock, який є членом екземпляра, матиме інше значення / посилання для кожного примірника вашого класу Hello, і тому ви не можете отримати доступ до нього зі статичної частини класу.


Велике пояснення статичного контексту :)
Абдель-Рауф

20

Статичний на Java:

Статичний - це модифікатор без доступу. Статичне ключове слово належить до класу, ніж екземпляр класу. можна використовувати для приєднання змінної чи методу до класу.

Статичне ключове слово МОЖЕ бути використане для:

Метод

Змінна

Клас вкладений в інший клас

Блок ініціалізації

НЕ можна використовувати з:

Клас (не вкладений)

Конструктор

Інтерфейси

Метод Локальний внутрішній клас (Різниця потім вкладений клас)

Методи внутрішнього класу

Змінні інстанції

Локальні змінні

Приклад:

Уявіть наступний приклад, який містить змінну екземпляра з назвою count, яка збільшується в конструкторі:

package pkg;

class StaticExample {
    int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

Вихід:

1 1 1

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

Тепер, якщо ми змінимо кількість змінних екземплярів на статичну, програма дасть різні результати:

package pkg;

class StaticExample {
    static int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

Вихід:

1 2 3

У цьому випадку статична змінна отримає пам'ять лише один раз, якщо будь-який об'єкт змінить значення статичної змінної, він збереже своє значення.

Статичний з фіналом:

Глобальна змінна, яка оголошена остаточною та статичною, залишається незмінною для всього виконання. Тому що Статичні члени зберігаються в пам'яті класу і вони завантажуються лише один раз у всьому виконанні. Вони загальні для всіх об'єктів класу. Якщо ви оголошуєте статичні змінні як кінцеві, будь-який з об'єктів не може змінити своє значення як остаточне. Тому змінні, оголошені як кінцеві та статичні, іноді називають константами. Усі поля інтерфейсів називаються константами, оскільки вони є остаточними та статичними за замовчуванням.

введіть тут опис зображення

Ресурс зображення: остаточний статичний


15

Щоб додати до існуючих відповідей, дозвольте спробувати картинку:

Процентна ставка в розмірі 2% застосовується до ВСІХ ощадних рахунків. Отже, вона статична .

Баланс повинен бути індивідуальним , тому він не є статичним.

введіть тут опис зображення


13

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


1
Про це Апокалісп згадував у коментарях до відповіді Мердада.
Зак Ленглі

1
Гарна думка. Багато людей цього не знають, але як тільки ви почнете возитися з навантажувачами, це стає дуже важливим.
sleske

2
Це все правда, але це не відповідає на питання. Це слід було розмістити як коментар.
Маркіз Лорн

7

Поле може бути призначене або класу, або екземпляру класу. За замовчуванням поля - це змінні екземпляри. При використанні staticполя стає перемінною класом, таким чином, існує одна і єдина clock. Якщо ви внесете зміни в одному місці, це видно скрізь. Екземпляри змінних цінностей змінюються незалежно одна від одної.


6

Ключове слово staticвикористовується для позначення поля чи методу як належності до самого класу, а не до екземпляра. Використовуючи ваш код, якщо об'єкт Clockстатичний, всі екземпляри Helloкласу будуть спільними для цього Clockчлена (поля) даних. Якщо зробити його нестатичним, кожен окремий екземпляр Helloможе мати унікальне Clockполе.

Проблема полягає в тому, що ви додали основний метод до свого класу, Helloщоб ви могли запустити код. Проблема тут полягає в тому, що основний метод є статичним і, як такий, він не може посилатися на нестатичні поля чи методи всередині нього. Вирішити це можна двома способами:

  1. Зробіть всі поля та методи Helloкласу статичними, щоб їх можна було посилати всередині основного методу. Це дійсно не добре робити (або неправильна причина, щоб зробити поле та / або метод статичним)
  2. Створіть екземпляр свого Helloкласу всередині основного методу та в першу чергу отримайте доступ до всіх його полів та методів так, як вони були призначені.

Для вас це означає наступну зміну вашого коду:

package hello;

public class Hello {

    private Clock clock = new Clock();

    public Clock getClock() {
        return clock;
    }

    public static void main(String args[]) {
        Hello hello = new Hello();
        hello.getClock().sayTime();
    }
}

6

У Java staticключове слово можна просто вважати таким, що вказує на таке:

"без огляду або стосунків до якогось конкретного примірника"

Якщо ви думаєте про staticце таким чином, стає легше зрозуміти його використання в різних контекстах, в яких він стикається:

  • staticПоле являє собою поле , яке належить до класу , а не до якоїсь - якої конкретної інстанції

  • staticСпосіб є спосіб , який не має поняття this; він визначений для класу і не знає про якийсь конкретний екземпляр цього класу, якщо не буде передано посилання на нього

  • staticКлас елемента є вкладений клас без якого - або поняття або знання примірника його вміщує класу (якщо посилання на охоплює екземпляр класу не передаються до нього)


5

Static робить член годинника членом класу замість члена екземпляра. Без статичного ключового слова вам потрібно створити екземпляр класу Hello (який має змінну члена годинника) - наприклад

Hello hello = new Hello();
hello.clock.sayTime();


5

Я розробив симпатію до статичних методів (лише, якщо можливо) у класах «помічників».

Класу виклику не потрібно створювати іншу змінну члена (екземпляра) допоміжного класу. Ви просто називаєте методи класу хелперів. Також поліпшується клас помічників, оскільки вам більше не потрібен конструктор, і вам не потрібні змінні члена (екземпляра).

Напевно, є й інші переваги.


4
//Here is an example 

public class StaticClass 
{
    static int version;
    public void printVersion() {
         System.out.println(version);
    }
}

public class MainClass 
{
    public static void main(String args[]) {  
        StaticClass staticVar1 = new StaticClass();
        staticVar1.version = 10;
        staticVar1.printVersion() // Output 10

        StaticClass staticVar2 = new StaticClass();
        staticVar2.printVersion() // Output 10
        staticVar2.version = 20;
        staticVar2.printVersion() // Output 20
        staticVar1.printVersion() // Output 20
    }
}

3

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


3

Розуміння статичних понять

public class StaticPractise1 {
    public static void main(String[] args) {
        StaticPractise2 staticPractise2 = new StaticPractise2();
        staticPractise2.printUddhav(); //true
        StaticPractise2.printUddhav(); /* false, because printUddhav() is although inside StaticPractise2, but it is where exactly depends on PC program counter on runtime. */

        StaticPractise2.printUddhavsStatic1(); //true
        staticPractise2.printUddhavsStatic1(); /*false, because, when staticPractise2 is blueprinted, it tracks everything other than static  things and it organizes in its own heap. So, class static methods, object can't reference */

    }
}

Другий клас

public class StaticPractise2 {
    public static void printUddhavsStatic1() {
        System.out.println("Uddhav");
    }

    public void printUddhav() {
        System.out.println("Uddhav");
    }
}

2

main() - статичний метод, який має два основні обмеження:

  1. Статичний метод не може використовувати нестатичний член даних або безпосередньо викликати нестатичний метод.
  2. this()і super()не може використовуватися в статичному контексті.

    class A {  
        int a = 40; //non static
        public static void main(String args[]) {  
            System.out.println(a);  
        }  
    }

Вихід: Помилка часу компіляції


1

До статичних змінних можна отримати доступ лише в статичних методах, тому, коли ми оголосимо статичні змінні, ці методи "Геттер" і "Сеттер" будуть статичними методами

статичні методи - це клас класу, до якого ми можемо отримати доступ, використовуючи ім'я класу

Наведений нижче приклад для отримання статичних змінних та параметрів:

public class Static 
{

    private static String owner;
    private static int rent;
    private String car;
    public String getCar() {
        return car;
    }
    public void setCar(String car) {
        this.car = car;
    }
    public static int getRent() {
        return rent;
    }
    public static void setRent(int rent) {
        Static.rent = rent;
    }
    public static String getOwner() {
        return owner;
    }

    public static void setOwner(String owner) {
        Static.owner = owner;
    }

}

1

Було поставлено питання тут про вибір слова «статичний» для цієї концепції. Це питання було дуплено, але я не думаю, що етимологія була чітко розглянута. Тому...


Це пов’язано з повторним використанням ключових слів, починаючи з C.

Розглянемо декларації даних в C (всередині функції функції):

    void f() {
        int foo = 1;
        static int bar = 2;
         :
    }

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

Java та подібні мови мають однакове поняття для даних. Дані можуть бути розподілені за екземпляром класу (на об'єкт) або один раз для всього класу. Оскільки Java прагне мати звичний синтаксис для програмістів на C / C ++, тут є ключовим словом "статичний".

    class C {
        int foo = 1;
        static int bar = 2;
         :
    }

І нарешті, ми приходимо до методів.

    class C {
        int foo() { ... }
        static int bar() { ... }
         :
    }

Концептуально кажучи, є примірник foo () для кожного примірника класу C. Існує лише один екземпляр bar () для всього класу C. Це паралельно випадку, про який ми обговорювали дані, і тому використовуємо 'static '- це знову розумний вибір, особливо якщо ви не хочете додавати до своєї мови більш зарезервовані ключові слова.

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