Почему "String variableName = variableName = value;"работает на Java? - PullRequest
0 голосов
/ 27 сентября 2019

Почему T variableName = variableName = value; работает в Java?где T может быть любого типа или даже примитива.

Integer v1 = v1 = 1; работает.Означает ли это, что объявление переменной имеет наивысший приоритет в выражении?Можете ли вы объяснить технические особенности, стоящие за этим?

Примечание. Весь вопрос был реорганизован / обновлен.Некоторые комментарии ниже могут быть вне контекста.

1 Ответ

0 голосов
/ 27 сентября 2019

Я попытаюсь ответить на это.Я должен уточнить, что этот ответ является чем-то вроде предположения, основанного на общих знаниях о том, как обычно работают языки программирования, а не на конкретных знаниях спецификации 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>, также должны быть запрещены, но ясно, что разработчики языка либо не соглашались, либо не думали об этом.

...