Инициализация статических полей final в Java - PullRequest
6 голосов
/ 13 мая 2011
public class Main {
 static final int alex=getc();
 static final int alex1=Integer.parseInt("10");
 static final int alex2=getc();

public static int getc(){
    return alex1;
}

public static void main(String[] args) {
    final Main m = new Main();
    System.out.println(alex+" "+alex1 +" "+alex2);
  } 
}

Может кто-нибудь сказать мне, почему это печатает: 0 10 10?Я понимаю, что это статическая конечная переменная, и ее значение не должно меняться, но немного сложно понять, как компилятор инициализирует поля.

Ответы [ 5 ]

6 голосов
/ 13 мая 2011

Это проблема заказа.Статические поля инициализируются в том порядке, в котором они встречаются, поэтому, когда вы вызываете getc () для инициализации переменной alex, alex1 еще не был установлен.Сначала нужно поставить инициализацию alex1, а затем вы получите ожидаемый результат.

4 голосов
/ 13 мая 2011

Эта ситуация описана в JLS 8.3.2.3"Ограничения на использование полей при инициализации".

Правила JLS разрешают использование в вашем Вопросе и утверждают, что первый вызов getc() вернет значение по умолчанию (неинициализированное) alex.

Однако правила запрещают использование неинициализированных переменных; например,

int i = j + 1;
int j = i + 1;

не разрешено.


Re некоторые другие ответы. Это не тот случай, когда компилятор Java "не может понять это". Компилятор строго реализует то, что указано в Спецификации языка Java. (Или, иначе говоря, можно написать компилятор , чтобы обнаружить округлость в вашем примере и назвать это ошибкой компиляции. Однако, если бы он это сделал, он отклонил бы действительные программы Java, и поэтому не будет совместимым компилятором Java.)


В комментарии вы заявляете это:

... конечные поля всегда должны быть инициализированы во время компиляции или во время выполнения до создания объекта.

Это не правильно.

На самом деле существует два вида полей final:

  • Так называемая «постоянная переменная» действительно оценивается во время компиляции. (Постоянная переменная - это переменная "примитивного типа или типа String, которая является конечной и инициализируется константным выражением времени компиляции" - см. JLS 4.12.4.). Такое поле всегда будет инициализировано к тому времени, когда вы получите к нему доступ ... по модулю некоторых осложнений, которые здесь не имеют отношения.

  • Другие поля final инициализируются в порядке, указанном JLS, и позволяет увидеть значение поля до его инициализации. Ограничение final переменных заключается в том, что они должны инициализироваться один раз и только один раз во время инициализации класса (для static) или во время инициализации объекта.


Наконец, этот материал очень похож на поведение в «угловом корпусе». Типичный хорошо написанный класс не нужно получить доступ к полю final до его инициализации.

4 голосов
/ 13 мая 2011

Статические конечные поля, значения которых не являются константными выражениями времени компиляции, инициализируются в порядке объявления.Таким образом, когда alex при инициализации, alex1 еще не инициализирован, так что getc() возвращает значения по умолчанию alex1 (0).

Обратите внимание, что результат будет другим (10 10 10) в следующем случае:

static final int alex1 = 10;

В этом случае alex1 инициализируется константным выражением времени компиляции, поэтому инициализируется с самого начала.

2 голосов
/ 13 мая 2011

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

например,

public class Main {
    private final int a;

    public Main() {
        System.out.println("Before a=10, a="+getA());
        this.a = 10;
        System.out.println("After a=10, a="+getA());
    }

    public int getA() {
        return a;
    }

    public static void main(String... args) {
        new Main();
    }
}

печать

Before a=10, a=0
After a=10, a=10
0 голосов
/ 13 мая 2011

Переменные класса не нужны для инициализации, они автоматически устанавливаются в значения по умолчанию. Если примитивы (например, int, short ...) это 0 (ноль) для объектов, то это null. Поэтому alex1 установлен в 0. Переменные метода должны быть инициализированы, в противном случае вы получите ошибку компиляции.

Для лучшего объяснения прочитайте http://download.oracle.com/javase/tutorial/java/javaOO/classvars.html

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