2009-03-03 5 views
3

Я побежал через класс, который был создан как это:Статические переменные и методы

public class MyClass { 

    private static boolean started = false; 

    private MyClass(){ 
    } 

    public static void doSomething(){ 
    if(started){ 
     return; 
    } 
    started = true; 
    //code below that is only supposed to run 
    //run if not started 
    } 
} 

Мое понимание со статическими методами является то, что вы не должны использовать переменные класса в них, если они не являются постоянными, а не изменить , Вместо этого вы должны использовать параметры. Мой вопрос: почему это не нарушается, когда вызывается несколько раз, выполняя MyClass.doSomething(). Мне кажется, что это не должно работать, но делает. Он будет проходить только после выполнения инструкции if.

Так может кто-нибудь объяснить мне, почему это не сломается?

ответ

11

Метод doSomething() и переменная started являются статическими, поэтому имеется только одна копия переменной и она доступна из doSomething(). В первый раз вызывается doSomething(), started является ложным, поэтому он устанавливает started в true, а затем делает ... ну, что-то. Второй и последующий раз, когда он называется, started - это правда, поэтому он возвращается, ничего не делая.

+0

Итак, вы говорите, что у вас есть только одна копия этого класса, которая будет инициализирована и использована в течение всего времени работы приложения? Меня беспокоило то, что я не был уверен, что каждый раз будет использоваться один и тот же экземпляр, и что значение переменной не будет последовательным. –

+0

+1 для правильного ответа.Кроме того, здесь можно получить дополнительную информацию о статических переменных в целом. Наверное, хорошо для вас читать, bigbrother82: http://en.wikipedia.org/wiki/Static_variable – Welbog

+0

@ bigbrother82: Есть несколько экземпляров класса, но только одна копия начатой ​​переменной, разделяемой между ними. – Welbog

1

В статическом методе вы можете вызвать или получить доступ к статическим членам в одном классе.

Отказ от сценариев с несколькими потоками, Первый вызов doSomething сделает логическую статическую переменную равной true, поэтому второй вызов будет выполнять код блока if, который просто просто выйдет из метода.

0

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

+0

Или это исключает. Тогда возникает вопрос о том, что на самом деле делает «код ниже». Предположительно, более злая изменчивая статика. –

0

Мое понимание со статическими методами является то, что вы не должны использовать переменные класса в них, если они не являются постоянными и не меняются

я думаю только статические члены могут быть доступны. Это не обязательно быть постоянным!

Мой вопрос: почему это не нарушается при вызове несколько раз, выполняя MyClass.doSomething(). Мне кажется, что это не должно работать, но делает. Он будет проходить только после заявления if

В соответствии с существующей логикой. Только первый вызов запускает //code to be run часть

6

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

Что должно случиться:

  1. Первый вызов сделан. Класс инициализирован, запущен false.
  2. doЧто-то называется. Ошибка if и код обходит его. start установлен в true и выполняется другой код.
  3. doSomething называется снова. Пропускание и выполнение останавливаются.

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

2

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

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

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

Вместо этого вы должны использовать параметры.

Это трудно понять, как бы быть использован started параметр - если вызывающий абонент знал, что был запущен процесс, почему они называют метод?

1

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

Если вы пытались получить доступ к нестатический переменной-члена:

private int foo = 0; 

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

started is false - initial state. 
MyClass.doSomething() - statered is now true 
MyClass.doSomething() - started is STILL true 

MyClass foo = new MyClass(); 
foo.started -> it's STILL true, because it's static 
foo.doSomething() - not sure you can do this in Java, but if you can, it's be STILL TRUE! 

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

6

Код не является потокобезопасным. Самый простой способ сделать этот код потокобезопасным будет делать что-то вроде

public class MyClass { 

    private static AtomicBoolean started = new AtomicBoolean(false); 

    private MyClass(){ 
    } 

    public static void doSomething(){ 
    boolean oldValue = started.getAndSet(true); 
    if (oldValue) 
     return; 
    } 

    //code below that is only supposed to run 
    //run if not started 
    } 
} 

Это должно быть поточно как синхронизирован AtomicBoolean getAndSet.

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

1

Просто помните правило большого пальца, что «Статические переменные класса уровня переменные и все не статические переменные экземпляра переменные». Тогда у вас не будет никакой путаницы!

i.e. Для статической переменной Все ссылки, сделанные в коде, имеют переменную точку в том же месте памяти. А для нестатической переменной новое распределение памяти выполняется всякий раз, когда создается новый экземпляр этого класса (поэтому каждая ссылка, сделанная в коде на переменную, указывает на другое место памяти, выделенное для вызова экземпляра класса).

Смежные вопросы