Содержание | Предыдущая | Следующая


ГЛАВА 16

Определяющее присваивание

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

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

Остальная часть от этой главы посвящена точному объяснению слов "значение, сообщенное определяющим присваиванием, перед". Идея состоит в том, что присваивание локальной переменной должно произойти, независимо от пути, который процесс проходит от начала конструктора, метода, или статического инициализатора, который содержит доступ, до места присваивания. Анализ принимает во внимание структуру операторов и выражений; также он обеспечивает специальную обработку выражений с операциями !, &&, ||, и ? :, операций &, |, ^, ==, и != с операндами типа boolean, константными логическими выражениями. Например, транслятор Явы распознает, что k имеет значение, сообщенное определяющим присваиванием, перед доступом (как параметр вызова метода) в примере:

{
	int k;
	if (v > 0 && (k = System.in.read()) >= 0)
		System.out.println(k);
}

 

потому, что доступ происходит только если значение выражения:

v > 0 && (k = System.in.read()) >= 0

является истинным, а это значение может быть true только если присваивание k выполнено (более правильно, вычислено). Аналогично, транслятор Явы распознает что в примере:

{
	int k;
	while (true) {
		k = n;
		if (k >= 5) break;
		n = 6;
	}
	System.out.println(k);
}

переменная k имеет определенное оператором while значение, потому, что условное выражение true никогда не будет иметь значение false, таким образом, только оператор break может нормально завершить оператор while, и k имеет значение, сообщенное определяющим присваиванием, перед оператором break.

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

{
	int k;
	int n = 5;
	if (n > 2)
		k = 3;
	System.out.println(k);		// k не имеет ”значение, сообщенное определяющим присваиванием, перед”


}

даже если значение n известно во время трансляции, и в принципе может быть известно во время трансляции, что присваивание k будет всегда выполняться (более правильно, вычисляться). Транслятор Явы должен действовать согласно правилам, приводящимся в этом разделе. Правила распознают только константные выражения; в этом примере, выражение n > 2 не является константным выражением как определено в §15.27.

В качестве другой иллюстрации, транслятор Явы принимает пример:

void flow(boolean flag) {
	int k;
	if (flag)
		k = 3;
	else
		k = 4;
	System.out.println(k);
}

какое бы значение, сообщенное определяющим присваиванием, k не имело, потому, что правила этой главы разрешают говорить, что k имеет значение независимо от того, является ли флаг true или false. Но по этим правилам следующий вариант неприемлем:

void flow(boolean flag) {
	int k;
	if (flag)
		k = 3;
	if (!flag)
		k = 4;
	System.out.println(k); 		// здесь  k не имеет ”значение, сообщенное определяющим присваиванием, перед”
}

таким образом трансляция этой программы должна выдать ошибку времени компиляции.

Чтобы точно определить все случаи определенного присваивания, правила в этом разделе выделяют два специальных термина:

Чтобы выделить логические выражения, последнее понятие разделяется на два случая:

Здесь, когда true и когда false относится к значению выражения. Например, локальная переменная k имеет значение, сообщенное определяющим присваиванием, после вычисления выражения

a && ((k=m) > 5)


когда выражение true, но не когда выражение false (потому что, если a есть false, то присваивание k не происходит (более правильно, не вычисляется)).

Утверждение "V имеет значение, сообщенное определяющим присваиванием, после X" (где V - локальная переменная, а X – выражение) означает "V имеет значение, сообщенное определяющим присваиванием, после X, если X завершается нормально". Если X завершается преждевременно, присваивание может не произойти, и правила, установленные здесь, принимают это во внимание. Специфическое следствие этого определения, что " V имеет значение, сообщенное определяющим присваиванием, после break; " всегда является истиной! Так как оператор break никогда не завершается нормально, это бессмысленная истина, что V присвоено значение, если оператор break завершается нормально.

Пусть V – локальная переменная. Пусть a, b, c, и e выражения. Пусть S и T – операторы.

16.1 Определяющее присваивание и выражения

16.1.1 Логические константные выражения

V имеет значение, сообщенное определяющим присваиванием, после любого константного выражения, чье значение есть true, когда ложь. V имеет значение, сообщенное определяющим присваиванием, после любого константного выражения, чье значение есть false, когда истина.

Константное выражение, чье значение есть true, никогда не имеет значение false, и константное выражение, чье значение есть false, никогда не имеет значение true. Эти определения полезны при анализе выражений, включающих логические операторы &&, ||, и ! (§16.1.3, §16.1.4, §16.1.5).

16.1.2 Логические выражения

Для каждого логического выражения:

16.1.3 Логическая операция &&

16.1.4 Логическая операция ||

16.1.5 Логическая операция !

16.1.6 Логическая операция &

16.1.7 Логическая операция |

16.1.8 Логическая операция ^

16.1.9 Логическая операция ==

16.1.10 Логическая операция !=

Правила для a != b идентичны правилам для a ^ b (§16.1.8).

16.1.11 Логическая операция ?:

Предположим, что b и c – логические выражения.

16.1.12 Условная операция ?:

Предположим, что b и c выражения, не являющиеся логическими.

16.1.13 Логические выражения присваивания

Предположим, что выражения присваивания a = b, a &= b, a |= b или a ^= b логические.

Обратите внимание, что если a есть V и V не имеет определенного значения перед составным присваиванием типа a =& b, то обязательно произойдет ошибка во время трансляции. Правила, установленные выше включают отдельное "a есть V " таким образом, чтобы V рассматривалось как имеющее значение, сообщенное определяющим присваиванием в дальнейших пунктах кода. Включение отдельного "a есть V" не воздействует на решение относительно того, является ли программа допустимой или приведет к ошибке во время трансляции, но это воздействует на то, сколько различных пунктов в программе могут рассматриваться как ошибочные, и это практически может улучшить качество сообщения об ошибке.

16.1.14 Другие выражения присваивания

Предположим, что выражения присваивания a = b, a += b, a –= b, a *= b, a /= b, a %= b, a <<= b, a >>= b, a >>>= b, a =& b, a |= b или a ^= b не являются логическими.

16.1.15 Операции ++ и --

16.1.16 Другие выражения

Если выражение не является логическим и не является выражением условной операции или выражением присваивания, то действуют следующие правила:

Для любого непосредственного подвыражения y выражения x, V имеет значение, сообщенное определяющим присваиванием, перед y, если и только если V имеет значение, сообщенное определяющим присваиванием, перед x или одно из следующих утверждений истинно:

 

16.2 Определяющее присваивание и операторы

16.2.1 Пустые операторы

16.2.2 Блоки

16.2.3 Операторы объявления локальной переменной

16.2.4 Помеченные операторы

16.2.5 Операторы-выражения

16.2.6 Операторы if

16.2.7 Операторы switch

16.2.8 Операторы while

16.2.9 Операторы do

16.2.10 Операторы for

16.2.10.1 Часть инициализации

16.2.10.2 Часть приращения

16.2.11 Операторы break, continue, return и throw

16.2.12 Операторы synchronized

16.2.13 Операторы try

V имеет значение, сообщенное определяющим присваиванием, перед блоком finally, если и только если V имеет значение, сообщенное определяющим присваиванием, перед оператором try.


Содержание | Предыдущая | Следующая