Что делает ключевое слово static в классе?


444

Чтобы быть конкретным, я пытался этот код:

package hello;

public class Hello {

    Clock clock = new Clock();

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

Но это дало ошибку

Невозможно получить доступ к нестатическому полю в статическом методе main

Поэтому я изменил декларацию clockна это:

static Clock clock = new Clock();

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


Еще раз помните, что на CLASSLOADER приходится один экземпляр статики на класс.
Javamann

Ответы:


634

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, так как это частная переменная? Или это действительно, потому что вы создали экземпляр объекта внутри его собственного класса? Звучит как рекурсивный кошмар для меня, но я новичок на Java.
Мэтт Корби

Если на статический член класса ссылаются 2 разных потока, то сколько существует экземпляров этого статического члена? Я чувствую, что это 2, но если вы хотите, чтобы один и тот же экземпляр в потоках, то необходимо использовать ключевое слово volatile. Это верно?
Дан

..и сохраняется ли значение, если не осталось экземпляров класса?
19

130

Это означает, что в Hello есть только один экземпляр «clock», а не по одному на каждый отдельный экземпляр класса «Hello», или более того, это означает, что среди всех экземпляров будет одна общедоступная ссылка «clock». класс "Привет".

Поэтому, если бы вы выполняли «новый Hello» где-нибудь в вашем коде: A- в первом сценарии (до изменения, без использования «static»), он делал бы новые часы каждый раз, когда вызывается «new Hello», но B- во втором сценарии (после изменения, используя «static»), каждый «новый Hello» экземпляр по-прежнему будет совместно использовать и использовать начальную и ту же самую ссылку «clock», которая была впервые создана.

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

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

Это более обычный способ сделать это. main()Процедура должна быть самодостаточной.
Джейсон С

1
Во втором случае он будет создавать новый экземпляр Clock каждый раз, когда вызывается основной метод, верно?
Нажмите Upvote

2
Во втором случае, clock static, он будет создан только один раз. В моем примере, где часы находятся в главном, тогда да, оно будет создавать его каждый раз, когда вызывается main. Но обычно main вызывается только один раз при запуске программы, и когда он выходит, все становится свободным.
Пол Томблин

Я не могу понять, как можно сделать новые часы в основном методе? как вы говорите, он будет создавать его каждый раз, когда вызывается main, но есть только один метод main. как этот основной метод может ссылаться на разные экземпляры часов? Немного сложно понять, как можно создать новый экземпляр часов в main и использовать его метод sayTime (), но невозможно сделать экземпляр из main и использовать sayTime (). как все бесплатно, когда main вызывается один раз? @PaulTomblin
ShakibaZar

@ user5621266 Я использовал этот mainметод только потому, что это сделал OP. Если вместо этого это был публичный метод, который вызывался из другого места, и класс Hello создавался более одного раза, то он мог бы создать экземпляр Clock для каждого экземпляра Hello, если только он не clockбыл статическим.
Пол Томблин

97

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

Для получения дополнительной информации см. Соответствующую часть Oracle Java Tutorial .


Примечание

К сожалению, 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 static принадлежит типу, а не объекту? Можете рассказать подробнее? Типа типа данных: 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 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:

Static - это не модификатор доступа. Ключевое слово static относится к классу, а не к экземпляру класса. может использоваться для присоединения переменной или метода к классу.

Статическое ключевое слово МОЖЕТ использоваться с:

метод

переменная

Класс, вложенный в другой класс

Блок инициализации

НЕ МОЖЕТ использоваться с:

Класс (не вложенный)

Конструктор

Интерфейсы

Метод Local Inner Class (отличие от вложенного класса)

Методы внутреннего класса

Переменные экземпляра

Локальные переменные

Пример:

Представьте себе следующий пример, в котором есть переменная экземпляра с именем 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

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

Статика с финалом:

Глобальная переменная, объявленная как final и static, остается неизменной на протяжении всего выполнения. Потому что статические члены хранятся в памяти классов и загружаются только один раз за все выполнение. Они являются общими для всех объектов класса. Если вы объявите статические переменные как окончательные, ни один из объектов не сможет изменить их значение, поскольку оно является окончательным. Поэтому переменные, объявленные как final и static, иногда называют константами. Все поля интерфейсов называются константами, потому что они являются окончательными и статическими по умолчанию.

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

Ресурс изображения: Final Static


15

Чтобы добавить к существующим ответам, позвольте мне попробовать с изображением:

Процентная ставка 2% применяется ко ВСЕМ сберегательным счетам. Следовательно это статично .

Баланс должен быть индивидуальным , чтобы он не был статичным.

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


13

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


1
Это было упомянуто Apocalisp в комментариях к ответу Мерхдада.
Зак Лэнгли

1
Хорошая точка зрения. Многие люди не знают этого, но как только вы начинаете возиться с загрузчиками классов, это становится очень важным.
Слеск

2
Это все правда, но это не отвечает на вопрос. Это должно было быть отправлено как комментарий.
Маркиз Лорн

7

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


6

Ключевое слово staticиспользуется для обозначения поля или метода как принадлежащих самому классу, а не экземпляру. Используя ваш код, если объект Clockстатический, все экземпляры Helloкласса будут совместно использовать этот Clockэлемент данных (поле) совместно. Если вы сделаете его нестатичным, каждый отдельный экземпляр Helloможет иметь уникальныйClock поле.

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

  1. Сделайте все поля и методы Helloкласса статическими, чтобы их можно было ссылаться внутри основного метода. Это действительно не очень хорошая вещь (или неправильная причина, по которой поле и / или метод становятся статическими)
  2. Создайте экземпляр вашего Helloкласса внутри метода main и получите доступ ко всем его полям и методам так, как они были предназначены в первую очередь.

Для вас это означает следующее изменение вашего кода:

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 делает член часов членом класса вместо члена экземпляра. Без ключевого слова static вам нужно было бы создать экземпляр класса Hello (который имеет переменную-член clock) - например,

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

Также можно думать о статических членах, не имеющих указателя «this». Они распределяются между всеми экземплярами.


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

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

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

Ниже приведен пример для статических переменных Getter и Setters:

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 ++, здесь уместно ключевое слово «static».

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

Наконец, мы приходим к методам.

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

Концептуально говоря, существует экземпляр функции foo () для каждого экземпляра класса C. Для всего класса C. существует только один экземпляр bar (). Это параллельно случаю, который мы обсуждали для данных, и, следовательно, с использованием 'static Это снова разумный выбор, особенно если вы не хотите добавлять больше зарезервированных ключевых слов на свой язык.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.