Подтвердить что ты не робот

Почему компилятор Java не понимает эту переменную, всегда инициализируется?

class Foo{
    public static void main(String args[]){
        final int x=101;

        int y;
        if(x>100){
            y=-1;
        }
        System.out.println(y);
    }
}

Java-компилятор понимает, что условие оператора if всегда истинно, и поэтому y всегда будет инициализироваться. Ошибка компиляции, как и ожидалось.

class Bar{
    public static void main(String args[]){
        final int x;
        x=101;

        int y;      
        if(x>100){
            y=-1;
        }
        System.out.println(y);
    }
}

Но когда я нарушаю объявление и инициализацию x на две строки, компилятор не кажется, что условие всегда истинно, и y всегда будет инициализироваться.

final int x;
x=101;
byte b;
b=x;
System.out.println(b);

То же самое происходит здесь, и компилятор дает потерю точности ошибок.

final int x=101;
byte b;
b=x;
System.out.println(b);

Опять же, компилятор может понять, что x находится внутри диапазона b.

4b9b3361

Ответ 1

Это связано с тем, как компилятор определяет, будет ли выполняться оператор или нет. Он определен в JLS # 16:

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

В вашем случае компилятор не может определить, что y определенно назначен и дает вам ошибку. Это связано с тем, что ему нужно будет определить, что условие всегда истинно, и это возможно только в том случае, если условие в if является постоянным выражением.

JLS # 15.28 определяет постоянные выражения:

Постоянное выражение времени компиляции представляет собой выражение, обозначающее значение примитивного типа или String, которое не завершается внезапно и составлено с использованием только следующего:

  • [...]
  • Простые имена (§6.5.6.1), которые относятся к постоянным переменным (§4.12.4).

JLS # 4.12.4 определяет переменные константы как:

Переменная примитивного типа или типа String, которая является окончательной и инициализирована выражением постоянной времени компиляции, называется постоянной переменной.

В вашем случае final int x = 101; является постоянной переменной, но final int x; x = 101; не является.

Ответ 2

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

См. Спецификацию языка Java Глава 16. Определенное присвоение

Критическое правило - это значение 16.2.7. если "Заявления" , "если (e) S". Правило для того, чтобы быть определенно назначенным, расширяется до:

V назначается после if (e) S, если и только если V назначен после S и V назначается после e, когда false.

y является соответствующим V. Он не назначен перед оператором if. Это действительно назначается после S, y = {y = -1;}, но нет ничего, что было бы назначено, когда x > 100 является ложным.

Таким образом, y не определенно назначается после оператора if.

Более полный анализ потока определит, что условие x > 100 всегда истинно, но компилятор требуется JLS для отклонения программы на основе этих конкретных правил.

Конечная переменная прекрасна. Правило на самом деле: -

"Это ошибка времени компиляции, если конечной переменной присвоено значение if он определенно не назначен (§16) непосредственно перед назначение".

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

Ответ 3

Что вы сделали для переменной x во втором коде, называется переменной blank final. Если конечная переменная не инициализируется при ее объявлении, она называется пустой конечной переменной.

Многие разработчики Java считают, что значение конечной переменной известно во время компиляции. Это не всегда верно. Говорят, что значение пустой конечной переменной НЕ известно во время компиляции. Следовательно, ваш второй код даст вам ошибку компиляции. Компилятор может видеть, что вы инициализировали окончательную переменную x, но компиляция не знает ее значения. Поэтому компилятор не может разрешить оператор if. Поэтому он считает, что переменная y не инициализируется.

Вы можете узнать больше о конечных переменных Java здесь.