У каждой локальной переменной должно быть определенно присвоенное значение, когда любой доступ его значения происходит. Доступ к его значению состоит из простого имени переменной, происходящей где угодно в выражении за исключением левого операнда простого оператора присваивания =.
Компилятор Java должен выполнить определенный консервативный анализ потоков, чтобы удостовериться, что для каждого доступа локальной переменной локальная переменная определенно присваивается перед доступом; иначе ошибка времени компиляции должна произойти.
Остаток от этой главы посвящается точному объяснению слов, "определенно присвоенных прежде". Идея состоит в том, что присвоение на локальную переменную должно произойти на каждом возможном пути выполнения к доступу с начала конструктора, метода, или статического инициализатора, который содержит доступ. Анализ принимает во внимание структуру операторов и выражений; это также обеспечивает специальный режим операторов выражения !, &&, ||, и ? :, операторы &, |, ^, ==, и != с boolean операнды, и оцененные булевской переменной константные выражения. Например, компилятор Java распознает это k определенно присваивается перед его доступом (как параметр вызова метода) в коде:
{
int k;
if (v > 0 && (k = System.in.read()) >= 0)
System.out.println(k);
}
потому что доступ происходит только если значение выражения:
v > 0 && (k = System.in.read()) >= 0
истина, и значение может быть true только если присвоение на k выполняется (более должным образом, оценивается). Точно так же компилятор Java распознает что в коде:
{
int k;
while (true) {
k = n;
if (k >= 5) break;
n = 6;
}
System.out.println(k);
}
переменная k определенно присваивается while оператор, потому что выражение условия true никогда не имеет значение false, так только break оператор может вызвать while оператор, чтобы обычно завершаться, и k определенно присваивается перед break оператор.
За исключением специального режима определенных булевых операторов и оцененных булевской переменной константных выражений, значения выражений не принимаются во внимание в анализе потоков. Например, компилятор Java должен произвести ошибку времени компиляции для кода:
{
int k;
int n = 5;
if (n > 2)
k = 3;
System.out.println(k); // k is not "definitely assigned" before this
}
даже при том, что значение n известен во время компиляции, и в принципе можно быть известно во время компиляции что присвоение на k будет всегда выполняться (более должным образом, оцениваться). Компилятор Java должен работать согласно правилам, размеченным в этом разделе. Правила распознают только константные выражения; в этом примере, выражении n>2 не константное выражение как определено в §15.27.
Как другой пример, компилятор Java примет код:
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 is not "definitely assigned" before here
}
и так компиляция этой программы должна заставить ошибку времени компиляции происходить.
Чтобы точно определить все случаи определенного присвоения, правила в этом разделе определяют два технических термина:
присваивается ли локальная переменная определенно перед оператором или выражением, и
присваивается ли локальная переменная определенно после оператора или выражения.
Чтобы определить оцененные булевской переменной выражения, последнее понятие усовершенствовано в два случая:
присваивается ли локальная переменная определенно после выражения когда истина, и
присваивается ли локальная переменная определенно после выражения когда ложь.
Здесь, когда истина и когда ложь обращаются к значению выражения. Например, локальная переменная k определенно присваивается значение после оценки выражения
a && ((k=m) > 5)
когда выражение true но не, когда выражение false (потому что, если afalse, тогда присвоение на k не выполняется (более должным образом, оценивается)).
Оператор "V определенно присваивается, после X" (то, где V локальная переменная и X, является оператором или выражением) означает "V, определенно присваивается после X, если X обычно завершается". Если X завершается резко, присвоение, возможно, не произошло, и правила, утвержденные здесь, принимают это во внимание. Специфическое последствие этого определения - то, что "V определенно присваивается после break;"всегда истина! Поскольку a 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 Оцененные булевской переменной Выражения
Для каждого оцененного булевской переменной выражения:
Если у выражения нет никаких подвыражений, V определенно присваивается после того, как эквивалентность выражения V определенно присваивается перед выражением. Этот случай применяется к литералам и простым именам.
Иначе, V определенно присваивается после того, как эквивалентность выражения V определенно присваивается после выражения, когда истина и V определенно присваивается после выражения когда ложь.
16.1.3 Булев оператор &&
V определенно присваивается после a&&b, когда истинная эквивалентность V определенно присваивается после, когда истина или V определенно присваивается после b когда истина.
V определенно присваивается после a&&b, когда ложная эквивалентность V определенно присваивается после, когда ложь и V определенно присваивается после b когда ложь.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается прежде a&&b.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после когда истина.
16.1.4 Булев оператор ||
V определенно присваивается после a||b, когда истинная эквивалентность V определенно присваивается после, когда истина и V определенно присваивается после b когда истина.
V определенно присваивается после a||b, когда ложная эквивалентность V определенно присваивается после, когда ложь или V определенно присваивается после b когда ложь.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается прежде a||b.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после когда ложь.
16.1.5 Булев оператор !
V определенно присваивается после !когда истинная эквивалентность V определенно присваивается после когда ложь.
V определенно присваивается после !когда ложная эквивалентность V определенно присваивается после когда истина.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается прежде !a.
16.1.6 Булев оператор &
V определенно присваивается после a&b, когда истинная эквивалентность V определенно присваивается после, когда истина или V определенно присваивается после b когда истина.
V определенно присваивается после a&b, когда ложная эквивалентность по крайней мере одно из следующего является истиной:
V определенно присваивается после b. (Отметьте что, если V определенно присваивается после a, из этого следует, что V определенно присваивается после b.)
V определенно присваивается после, когда ложь и V определенно присваивается после b когда ложь.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается прежде a&b.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после a.
16.1.7 Булев оператор |
V определенно присваивается после a|b, когда истинная эквивалентность по крайней мере одно из следующего является истиной:
V определенно присваивается после b. (Отметьте что, если V определенно присваивается после a, из этого следует, что V определенно присваивается после b.)
V определенно присваивается после, когда истина и V определенно присваивается после b когда истина.
V определенно присваивается после a|b, когда ложная эквивалентность V определенно присваивается после, когда ложь или V определенно присваивается после b когда ложь.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается прежде a|b.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после a.
16.1.8 Булев оператор ^
V определенно присваивается после a^b, когда истинная эквивалентность по крайней мере одно из следующего является истиной:
V определенно присваивается после b.
V определенно присваивается после, когда истина и V определенно присваивается после b когда истина.
V определенно присваивается после, когда ложь и V определенно присваивается после b когда ложь.
V определенно присваивается после a^b, когда ложная эквивалентность по крайней мере одно из следующего является истиной:
V определенно присваивается после b.
V определенно присваивается после, когда истина и V определенно присваивается после b когда ложь.
V определенно присваивается после, когда ложь и V определенно присваивается после b когда истина.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается прежде a^b.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после a.
16.1.9 Булев оператор ==
V определенно присваивается после a==b, когда истинная эквивалентность по крайней мере одно из следующего является истиной:
V определенно присваивается после b.
V определенно присваивается после, когда истина и V определенно присваивается после b когда ложь.
V определенно присваивается после, когда ложь и V определенно присваивается после b когда истина.
V определенно присваивается после a==b, когда ложная эквивалентность по крайней мере одно из следующего является истиной:
V определенно присваивается после b.
V определенно присваивается после, когда истина и V определенно присваивается после b когда истина.
V определенно присваивается после, когда ложь и V определенно присваивается после b когда ложь.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается прежде a==b.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после a.
16.1.10 Булев оператор !=
Правила для a!=b идентичны правилам для a^b(§16.1.8).
16.1.11 Булев оператор ? :
Предположите, что b и c являются оцененными булевской переменной выражениями.
V определенно присваивается после a?b:c, когда истинная эквивалентность оба из следующего истина:
V определенно присваивается, прежде b или V определенно присваивается после b когда истина.
V определенно присваивается, прежде c или V определенно присваивается после c когда истина.
V определенно присваивается после a?b:c, когда ложная эквивалентность оба из следующего истина:
V определенно присваивается, прежде b или V определенно присваивается после b когда ложь.
V определенно присваивается, прежде c или V определенно присваивается после c когда ложь.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается прежде a?b:c.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после когда истина.
V определенно присваивается, прежде c эквивалентность V определенно присваивается после когда ложь.
16.1.12 Условный Оператор ? :
Предположите, что b и c являются выражениями, которые не оцениваются булевской переменной.
V определенно присваивается после a?b:c эквивалентность оба из следующего истина:
V определенно присваивается после b.
V определенно присваивается после c.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается прежде a?b:c.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после когда истина.
V определенно присваивается, прежде c эквивалентность V определенно присваивается после когда ложь.
16.1.13 Булевы Выражения Присвоения
Предположите что выражение a присвоения =b, a&=b, a|=b, или a^=b является булевской переменной - оцененный.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается перед выражением присвоения.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после a.
V определенно присваивается после a=b, когда истинная эквивалентность или V или V определенно присваивается после правого выражения операнда когда истина.
V определенно присваивается после a=b, когда ложная эквивалентность или V или V определенно присваивается после правого выражения операнда когда ложь.
V определенно присваивается после a&=b, когда истинная эквивалентность или V или V был бы определенно присвоен после a&b (в том же самом контексте), когда истина.
V определенно присваивается после a&=b, когда ложная эквивалентность или V или V был бы определенно присвоен после a&b (в том же самом контексте), когда ложь.
V определенно присваивается после a|=b, когда истинная эквивалентность или V или V был бы определенно присвоен после a|b (в том же самом контексте), когда истина.
V определенно присваивается после a|=b, когда ложная эквивалентность или V или V был бы определенно присвоен после a|b (в том же самом контексте), когда ложь.
V определенно присваивается после a^=b, когда истинная эквивалентность или V или V был бы определенно присвоен после a^b (в том же самом контексте), когда истина.
V определенно присваивается после a^=b, когда ложная эквивалентность или V или V был бы определенно присвоен после a^b (в том же самом контексте), когда ложь.
Отметьте это, если V и V определенно не присваивается перед составным присвоением, таким как a&=b, затем ошибка времени компиляции обязательно произойдет. Вышеизложенные правила включают разобщенное "V" так, чтобы V, как полагали, был определенно присвоен в более поздних точках в коде. Включая разобщенное "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 не оценивается булевской переменной.
V определенно присваивается после эквивалентности выражения присвоения или V или V определенно присваивается после b.
V определенно присваивается прежде, чем эквивалентность V определенно присваивается перед выражением присвоения.
V определенно присваивается, прежде b эквивалентность V определенно присваивается после a.
16.1.15 Операторы ++ и --
V определенно присваивается после предынкремента, преддекремента, постинкремента, или постдекрементной эквивалентности выражения или выражение операнда V или V, определенно присваивается после выражения операнда.
V определенно присваивается прежде, чем эквивалентность выражения операнда V определенно присваивается перед предынкрементом, преддекрементом, постинкрементом, или постдекрементным выражением.
16.1.16 Другие Выражения
Если выражение не оценивается булевской переменной и не является выражением условного оператора или выражением присвоения, следующие правила применяются:
Если у выражения нет никаких подвыражений, V определенно присваивается после того, как эквивалентность выражения V определенно присваивается перед выражением. Этот случай применяется к литералам, простым именам, this, super, и null.
Если у выражения есть подвыражения, V определенно присваивается после того, как эквивалентность выражения V определенно присваивается после ее самого правого непосредственного подвыражения.
Для любого непосредственного подвыражения yвыражения x, V определенно присваивается, прежде y эквивалентность V определенно присваивается, прежде x или одна из следующих ситуаций истина:
y является правым операндом бинарного оператора, и V определенно присваивается после левого операнда.
x является ссылкой массива, y является подвыражением в пределах скобок, и V определенно присваивается после подвыражения перед скобками.
x является выражением вызова метода для объекта; y является первым выражением параметра в выражении вызова метода; есть подвыражение, значение которого является объектом налево от точки, имени метода, и левой круглой скобки выражения вызова метода; и V определенно присваивается после этого подвыражения.
x является выражением вызова метода или выражением создания экземпляра класса; y является выражением параметра, но не первым; и V определенно присваивается после выражения параметра налево от y.
x является выражением создания экземпляра класса; y является выражением размерности, но не первым; и V определенно присваивается после выражения размерности налево от y.
16.2 Определенное Присвоение и Операторы
16.2.1 Пустые Операторы
V определенно присваивается после пустой эквивалентности оператора это определенно присваивается перед пустым оператором.
16.2.2 Блоки
V определенно присваивается после пустой блочной эквивалентности это определенно присваивается перед пустым блоком.
V определенно присваивается после непустой блочной эквивалентности это определенно присваивается после последнего оператора в блоке.
V определенно присваивается перед первым оператором блочной эквивалентности это определенно присваивается перед блоком.
V определенно присваивается перед любым другим оператором S блочной эквивалентности это определенно присваивается после оператора, сразу предшествующего S в блоке.
16.2.3 Операторы объявления Локальной переменной
V определенно присваивается после оператора объявления локальной переменной, который не содержит эквивалентности инициализаторов, он определенно присваивается перед оператором объявления локальной переменной.
V определенно присваивается после оператора объявления локальной переменной, который содержит эквивалентность инициализаторов или она определенно присваивается после того, как последнее выражение инициализатора в операторе объявления локальной переменной или последнее выражение инициализатора в объявлении находятся в операторе объявления, который объявляет V.
V определенно присваивается перед первой эквивалентностью выражения инициализатора это определенно присваивается перед оператором объявления локальной переменной.
V определенно присваивается перед любой другой эквивалентностью выражения e инициализатора или это определенно присваивается после того, как выражение инициализатора, сразу предшествующее e в операторе объявления локальной переменной или выражении инициализатора, сразу предшествующем e в операторе объявления локальной переменной, находится в операторе объявления, который объявляет V.
16.2.4 Помеченные операторы
V определенно присваивается после помеченного оператора L:S (где L является меткой) эквивалентность V определенно присваивается, после S и V определенно присваивается перед каждым break оператор, который может выйти из помеченного оператора L:S.
V определенно присваивается, прежде S эквивалентность V определенно присваивается прежде L:S.
16.2.5 Операторы выражения
V определенно присваивается после оператора e выражения; эквивалентность это определенно присваивается после e.
V определенно присваивается, прежде e эквивалентность это определенно присваивается прежде e;.
16.2.6 if Операторы
V определенно присваивается после if(e)S эквивалентность V определенно присваивается, после S и V определенно присваивается после e когда ложь.
V определенно присваивается, прежде e эквивалентность V определенно присваивается прежде if(e)S.V определенно присваивается, прежде S эквивалентность V определенно присваивается после e когда истина.
V определенно присваивается после if(e)SelseT эквивалентность V определенно присваивается, после S и V определенно присваивается после T.
V определенно присваивается, прежде e эквивалентность V определенно присваивается прежде if(e)SelseT.V определенно присваивается, прежде S эквивалентность V определенно присваивается после e когда истина. V определенно присваивается, прежде T эквивалентность V определенно присваивается после e когда ложь.
16.2.7 switch Операторы
V определенно присваивается после a switch эквивалентность оператора оба из следующего является истиной:
Любой switch блок пуст, или V определенно присваивается после последнего оператора switch блок.
V определенно присваивается перед каждым break оператор, который может выйти switch оператор.
V определенно присваивается прежде, чем эквивалентность выражения переключателя V определенно присваивается перед switch оператор.
V определенно присваивается перед оператором или оператором объявления S локальной переменной в блочной эквивалентности переключателя по крайней мере одно из следующего является истиной:
V определенно присваивается после выражения переключателя.
S не маркируется a case или default метка и V определенно присваивается после предыдущего оператора.
16.2.8 while Операторы
V определенно присваивается после while(e)S эквивалентность V определенно присваивается после e, когда ложь и V определенно присваивается перед каждым break оператор, который может выйти while оператор.
V определенно присваивается, прежде e эквивалентность V определенно присваивается перед while оператор.
V определенно присваивается, прежде S эквивалентность V определенно присваивается после e когда истина.
16.2.9 do Операторы
V определенно присваивается после doSwhile(e); эквивалентность V определенно присваивается после e, когда ложь и V определенно присваивается перед каждым break оператор, который может выйти do оператор.
V определенно присваивается, прежде S эквивалентность V определенно присваивается перед do оператор.
V определенно присваивается, прежде e эквивалентность V определенно присваивается, после S и V определенно присваивается перед каждым continue оператор, который может выйти из тела do оператор.
16.2.10 for Операторы
V определенно присваивается после a for эквивалентность оператора оба из следующего является истиной:
Или выражение условия не присутствует или V, определенно присваивается после выражения условия когда ложь.
V определенно присваивается перед каждым break оператор, который может выйти for оператор.
V определенно присваивается перед частью инициализации for эквивалентность оператора V определенно присваивается перед for оператор.
V определенно присваивается перед частью условия for эквивалентность оператора V определенно присваивается после части инициализации for оператор.
V определенно присваивается перед содержавшей эквивалентностью оператора любое из следующего является истиной:
Выражение условия присутствует, и V определенно присваивается после выражения условия когда истина.
Никакое выражение условия не присутствует, и V определенно присваивается после части инициализации for оператор.
V определенно присваивается перед частью приращения for эквивалентность оператора V определенно присваивается после того, как содержавший оператор и V определенно присваивается перед каждым continue оператор, который может выйти из тела for оператор.
16.2.10.1 Часть инициализации
Если часть инициализации for оператор является оператором объявления локальной переменной, правила §16.2.3 применяются.
Иначе, если часть инициализации пуста, то V определенно присваивается после того, как эквивалентность части инициализации V определенно присваивается перед частью инициализации.
Иначе, три правила применяются:
V определенно присваивается после того, как эквивалентность части инициализации V определенно присваивается после последнего оператора выражения в части инициализации.
V определенно присваивается прежде, чем первый оператор выражения в эквивалентности части инициализации V определенно присваивается перед частью инициализации.
V определенно присваивается прежде, чем оператор E выражения кроме первого в эквивалентности части инициализации V определенно присваивается после оператора выражения, сразу предшествующего E.
16.2.10.2 Часть приращения
Если часть приращения for оператор пуст, тогда V определенно присваивается после того, как эквивалентность части приращения V определенно присваивается перед частью приращения.
Иначе, три правила применяются:
V определенно присваивается после того, как эквивалентность части приращения V определенно присваивается после последнего оператора выражения в части приращения.
V определенно присваивается прежде, чем первый оператор выражения в эквивалентности части приращения V определенно присваивается перед частью приращения.
V определенно присваивается прежде, чем оператор E выражения кроме первого в эквивалентности части приращения V определенно присваивается после оператора выражения, сразу предшествующего E.
16.2.11 break, continue, return, и throw Операторы
Условно, мы говорим, что V определенно присваивается после любого break, continue, return, или throw оператор. Понятие, что переменная "определенно присваивается после" оператора или выражения действительно, означает, "определенно присваивается после оператора или выражения обычно завершается". Поскольку a break, continue, return, или throw оператор никогда обычно не завершается, он вырождено удовлетворяет это понятие.
В a return оператор с выражением или a throw оператор, V определенно присваивается прежде, чем эквивалентность выражения V определенно присваивается перед return или throw оператор.
16.2.12 synchronized Операторы
V определенно присваивается после synchronized(e)S эквивалентность V определенно присваивается после S.
V определенно присваивается, прежде e эквивалентность V определенно присваивается перед оператором synchronized(e)S.
V определенно присваивается, прежде S эквивалентность V определенно присваивается после e.
16.2.13 try Операторы
V определенно присваивается после a try эквивалентность оператора одно из следующего является истиной:
V определенно присваивается после того, как блок попытки и V определенно присваивается после каждого блока выгоды в операторе попытки.
try у оператора есть a finally блок и V определенно присваивается после finally блок.
V определенно присваивается перед try блочная эквивалентность V определенно присваивается перед try оператор.
V определенно присваивается прежде a catch блочная эквивалентность V определенно присваивается перед try оператор.
V определенно присваивается прежде a finally блочная эквивалентность V определенно присваивается перед try оператор.