Я попытаюсь ответить на это.Я должен уточнить, что этот ответ является чем-то вроде предположения, основанного на общих знаниях о том, как обычно работают языки программирования, а не на конкретных знаниях спецификации Java.
Во-первых, я могу подтвердить, что такая ситуация возникает в скомпилированной Java, а не только JShell.
Вот что, я думаю, происходит:
Означает ли это, что объявление переменной имеет наивысший приоритет в выражении?
Сортироватьиз (и возможно - см. невероятно полезный комментарий @ user207421 ниже).
Мы должны подумать о том, как компилятор может превратить этот код в работоспособный машинный код.Как правило, языки управляют локальной памятью, используя стек , каждый вызов метода / функции вызывает выделение новой области памяти ( frame ) в верхней частистек.Когда функция завершается, стек извлекается, и эта область памяти освобождается.Для эффективной работы большинство языков требуют знать, сколько памяти потребуется для стекового фрейма конкретной функции во время компиляции.Таким образом, для построения и разматывания стека во время выполнения не требуется (или очень мало) кода ветвления.
Как компилятор определяет, сколько памяти требуется каждому фрейму стека?Проще говоря, этого достаточно для каждого параметра и локальной переменной, объявленной в теле этой функции.
Итак, когда функция вызывается во время выполнения, выделяется достаточно памяти для всего кадра на вершине стека, с пробелом для каждой переменной и параметра.Это означает, что во время выполнения каждая переменная фактически «объявляется», как только начинает выполняться код содержащей ее функции, поэтому любое присвоение этому vaiarble (то есть =
) является безопасным для памяти в любой точке во времятело функции.
Следовательно, T x = x = <some value>
совершенно безопасно.Правостороннее назначение происходит первым, а левостороннее (фактически бездействие) - вторым.Декларация T x
для всех практических целей была поднята до верха всей функции, так что даже первый .
Почему путаница?
Как правило,мы склонны говорить что-то вроде «Переменная не может быть использована до ее объявления» .Но практически это чрезмерная генерализация, охватывающая две вещи:
- Переменная не может быть прочитана или записана, когда пространство для хранения не выделено
- Переменная должна нечитать до того, как оно будет впервые назначено
Первое требование в значительной степени покрыто выше.
Второй запрос касается обеспечения логической согласованности - если переменная hasn 'Если он еще не был назначен, сегмент памяти, который представляет его, не может содержать полезное значение, поэтому чтение его будет логической ошибкой.Это правило семантически обеспечивается компилятором;нет технической причины, по которой его нужно применять (особенно для примитивов), но он представляет собой логическую ошибку или, что еще хуже, ошибку безопасности.Однако код T x = x = <some value>
не нарушает это правило.Первый раз x
- read - во время назначения левой руки, которое происходит после назначения правой руки.Альтернативное утверждение, такое как boolean x = x == true
, действительно не компилируется.
Это оставляет нам только одну вещь для рассмотрения.Что не так с кодом вроде:
x = 7;
int x;
С точки зрения времени выполнения, здесь все в порядке.Однако это значительно усложняет работу компилятора.Чтобы выполнить проверку типа, компилятор должен будет прочитать до объявления int x;
, чтобы определить, что x = 7;
является допустимым оператором.Это основная техническая причина, по которой я могу придумать, почему спецификация языка хотела бы запретить такой код.
Фактически мы говорим:
Объявления переменныхподнимаются на вершину функции во время выполнения, но должны происходить до того, как будет сделана какая-либо ссылка на эту переменную во время компиляции.
Есть еще одна простая причина, по которой можно запретить объявлять переменную после ее первого назначения: это делает код неясным для чтения людьми.Точно так же можно утверждать, что такие утверждения, как T x = x = <some value>
, также должны быть запрещены, но ясно, что разработчики языка либо не соглашались, либо не думали об этом.