Есть ли разница между непосредственным назначением конечной переменной и назначением конечной переменной в конструкторе? - PullRequest
6 голосов
/ 02 декабря 2011

Есть ли разница между этими двумя инициализациями конечной переменной value?

class Test {
    final int value = 7;
    Test() {}
}

и

class Test {
    final int value;
    Test() {
        value = 7;
    }
}

-

РЕДАКТИРОВАТЬ: Более сложный пример, включающий подклассы.«0» выводится на стандартный вывод в этом случае, но 7 выводится, если я назначаю значение напрямую.

import javax.swing.*;
import java.beans.PropertyChangeListener;

class TestBox extends JCheckBox {

    final int value;

    public TestBox() {
        value = 7;
    }

    public void addPropertyChangeListener(PropertyChangeListener l) {
        System.out.println(value);
        super.addPropertyChangeListener(l); 
    }

    public static void main(String... args) {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        frame.setContentPane(panel);
        panel.add(new TestBox());
        frame.pack();
        frame.setVisible(true);
    }
}

Ответы [ 7 ]

4 голосов
/ 02 декабря 2011

Существует различие в уровне байт-кода:

Исходный код:

  final int value;

  public TestBox() {
      value = 7;
  }

Создает следующий код из addPropertyChangeListener:

   0:   getstatic       #3; 
   3:   aload_0
   4:   getfield        #2; 
   7:   invokevirtual   #4; 

И исходный код:

final int value = 7;

public TestBox() {      
}

Создает следующий код из addPropertyChangeListener:

   0:   getstatic       #3; 
   3:   bipush  7
   5:   invokevirtual   #4; 

Так что есть небольшая разница. Но не практично.

Кажется, что компилятор может обрабатывать конечную переменную как константу, если она инициализирована в операторе определения. Разные компиляторы могут делать это по-разному.

2 голосов
/ 02 декабря 2011

Попробовал на очень простом примере, и да, когда значение получено в конструкторе родителя, оно унифицируется (как и должно быть), , если не является окончательным и не инициализируется при объявлении.Процесс описан EJP, но с шагом # 0: финалы инициализируются указанным значением, если оно есть.

1 голос
/ 02 декабря 2011

Распространенной ошибочной интерпретацией конечной переменной является то, что она не может изменить свое значение.Фактическое значение окончательного модификатора (JLS 4.5.4) заключается в том, что «конечная переменная может быть назначена только один раз».

Вы столкнулись с одной из ситуаций, когда можно оценитьназывается «пустой финальной» (объявленной, но еще не назначенной) переменной, так что она оценивается как значение по умолчанию для указанного типа данных, даже если позднее ей присвоено другое значение.

0 голосов
/ 02 декабря 2011

Конструктор выполняется в следующем порядке:

  1. super () вызывается.
  2. Локальные переменные инициализируются и вызываются анонимные блоки инициализатора {}.
  3. Код в самом конструкторе называется. Обратите внимание, что если конструктор явно вызывает саму super (), об этом позаботятся в # 1.

Таким образом, ответ на ваш вопрос заключается в том, что инициализация будет перемещена с # 2 в версии объявления с инициализатором на # 3 в версии initialize-in-constructor. Однако, если у вас нет анонимных блоков инициализатора {} или, возможно, полей, которые были инициализированы с использованием предыдущих инициализаций других полей, было бы невозможно определить разницу.

0 голосов
/ 02 декабря 2011

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

  1. Если переменная является конечной и ей присвоено фиксированное значение в конструкторе, нет необходимости назначать ее в конструкторе.
  2. Если переменная является конечной и ей присваиваются разные значения, переданные в качестве аргумента в конструкторе, то вам необходимо назначить ее в конструкторе.

В основном используется первый случай. Потому что, насколько я знаю, конечные переменные - это не что иное, как константы.

0 голосов
/ 02 декабря 2011

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

0 голосов
/ 02 декабря 2011

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

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