В чем заключается правильная или принципиальная разница инициализации переменной stati c тем или иным образом на языке Java? - PullRequest
2 голосов
/ 04 мая 2020

Я немного сомневаюсь в правильном способе инициализации переменных stati c.

Я понял, что могу напрямую присвоить значение переменной static во время определения, например: в:

public class MyClass {
  // Direct initialization
  public static int counter = 0;

Кроме того, я видел, что вы можете использовать блок static, как в:

public class MyClass {
  public static int counter;

  static {
    counter = 0;
  }
}

Даже я неожиданно увидел, что вы также можете получить доступ к static переменные из конструкторов классов и установите их значение оттуда, как в:

public class MyClass {
  public static int counter;

  public MyClass() {
    this.counter = 0;
  }

  public MyClass( int a ) {
    this.counter = a;
  }
}

Мой вопрос: Каков правильный путь или основное различие между использованием того или иного типа инициализации при работе с переменными stati c?

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

public class StaticVariable {
    static int a = 0;

    public StaticVariable( int b ) {
        // The constructor parameter b is ignored
        System.out.println( "[Inside 1-parameter constructor] Current value of \"a\": " + a + " ." );
        System.out.println( "[Inside 1-parameter constructor] Value of \"a\" was increased in one ..." );
      a++;
    }

    public StaticVariable() {
        System.out.println( "[Inside parameterless constructor] Current value of \"a\": " + a + " ." );
        System.out.println( "[Inside parameterless constructor] Value of \"a\" was increased in one ..." );
      a++;
    }

    static {
        System.out.println( "[Inside static block] Initial value of \"a\": " + a + " ." );  
        System.out.println( "[Inside static block] Value of \"a\" was increased in one ..." );
      a++;
    }

    public static void main( String[] args ) {
        System.out.println( "[main method] Current value of \"a\": " + StaticVariable.a + " ." );
        StaticVariable object = new StaticVariable();
        System.out.println( "[main method] Current value of \"a\": " + StaticVariable.a + " ." );
        StaticVariable object2 = new StaticVariable( 10 );
        System.out.println( "[main method] Current value of \"a\": " + StaticVariable.a );
        System.out.println( "[main method] Directly setting value of \"a\" with 560" );
        StaticVariable.a = 560;
        System.out.println( "Updated value of \"a\": " + StaticVariable.a );
    }
}

Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 04 мая 2020

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

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

Третий пример семантически отличается. Установщик фактически не инициализирует переменную stati c. Это повторная инициализация переменной. (Вы можете вызвать получатель перед вызовом установщика, и это покажет вам действительное начальное значение; т. Е. Ноль.)

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

(Последний пример, похоже, не подходит, поэтому я его проигнорирую.)

В некоторых случаях невозможно выполнить необходимую инициализацию в одном выражении. (Например, может потребоваться выполнить последовательность операторов для заполнения объекта, или перехватить и обработать исключение, или иметь дело с final объектами 1 , которые ссылаются друг на друга.) В этих случаях Блок static - это возможные решения.


Существует ли "основная разница" между первыми двумя подходами?

Я так не думаю.

static Foo foo = <expression>;   // where this is legal Java code

на 100% семантически эквивалентен:

static Foo foo;
static {
    foo = <expression>;
}

Просто есть некоторые вещи, которые вы можете сделать с блоком stati c, которые вы не можете сделать с простым инициализатором. Блок stati c может быть более сложным, чем отдельный оператор присваивания.


1 - я «не в курсе» терминологии. На самом деле переменные final не являются объектами.

2 голосов
/ 04 мая 2020

Первый и второй подходы эквивалентны. Как правило, вы найдете первый подход гораздо более распространенным для простых инициализаций одной переменной. Но иногда инициализация stati c в блоке может быть удобной для более сложных ситуаций, например, добавление нескольких элементов в коллекцию, которая является переменной static, например:

static List<String> list;
static {
  list = new ArrayList<>();
  list.add("hello");
  list.add("world");
}

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

1 голос
/ 04 мая 2020

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

среди настроек непосредственно или в блоке stati c, я лично предпочитаю прямой, потому что он более понятен и читаем другие пользователи.

...