Вопрос

Я наткнулся на класс, который был настроен следующим образом:

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 будет передан только один раз.

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

Это было полезно?

Решение

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

Другие советы

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

Что должно произойти:

  1. Сделан первый звонок.Класс инициализирован, значение start — false.
  2. doSomething называется.if терпит неудачу, и код обходит его.для параметра start установлено значение true, и запускается другой код.
  3. doSomething вызывается снова.if проходит и выполнение останавливается.

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

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

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 синхронизируется.

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

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

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

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

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

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

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

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

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

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

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!

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

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

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

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

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

Я предполагаю, что доступны только статические члены.Оно не должно быть постоянным!

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top