Глава 16. Определённое присваивание
Содержание
- 16.1. Определённое присваивание и выражения
-
- 16.1.1. Булевы константные выражения
- 16.1.2. Оператор логического И
&& - 16.1.3. Оператор логического ИЛИ
|| - 16.1.4. Оператор логического отрицания
! - 16.1.5. Условный оператор
? : - 16.1.6.
switchВыражения - 16.1.7. Другие выражения типа
boolean - 16.1.8. Выражения присваивания
- 16.1.9. Операторы
++и-- - 16.1.10. Другие выражения
- 16.2. Определённое присваивание и операторы
-
- 16.2.1. Пустые операторы
- 16.2.2. Блоки
- 16.2.3. Локальные классы и интерфейсы
- 16.2.4. Операторы объявления локальных переменных
- 16.2.5. Операторы с метками
- 16.2.6. Операторы выражений
- 16.2.7.
ifОператоры - 16.2.8.
assertОператоры - 16.2.9.
switchОператоры - 16.2.10.
whileОператоры - 16.2.11.
doОператоры - 16.2.12.
forОператоры - 16.2.13.
break,yield,continue,returnиthrowОператоры - 16.2.14.
synchronizedОператоры - 16.2.15.
tryОператоры
- 16.3. Определённое присваивание и параметры
- 16.4. Определённое присваивание и инициализаторы массивов
- 16.5. Определённое присваивание и константы перечислений
- 16.6. Определённое присваивание и анонимные классы
- 16.7. Определённое присваивание и членские классы и интерфейсы
- 16.8. Определённое присваивание и статические инициализаторы
- 16.9. Определённое присваивание, конструкторы и инициализаторы экземпляров
Каждая локальная переменная, объявленная оператором (§14.4.2, §14.14.1, §14.14.2, §14.20.3) и каждое пустое final поле (§4.12.4, §8.3.1.2) должны иметь определённое значение, когда происходит любой доступ к его значению.
Доступ к его значению состоит из простого имени переменной (или, для поля, простого имени поля, квалифицированного this) в любом выражении, кроме как левого операнда простого оператора присваивания = (§15.26.1).
Для каждого доступа к локальной переменной, объявленной оператором x, или пустому final полю x, x должно быть определённо присвоено перед доступом, в противном случае возникает ошибка компиляции.
Аналогично, каждая пустая final переменная должна быть присвоена не более одного раза; она должна быть определённо не присвоена, когда происходит присваивание ей.
Такое присваивание происходит тогда и только тогда, когда простое имя переменной (или, для поля, его простое имя, квалифицированное this) находится в левой части оператора присваивания.
Для каждого присваивания пустой final переменной переменная должна быть определённо не присвоена перед присваиванием, в противном случае возникает ошибка компиляции.
Обратите внимание, что локальные переменные, объявленные шаблоном (§14.30), не подчиняются правилам определённого присваивания. Каждая локальная переменная, объявленная шаблоном, инициализируется в процессе сопоставления шаблонов и, следовательно, всегда имеет значение при доступе.
Остальная часть этой главы посвящена точному объяснению слов «определённо присвоено перед» и «определённо не присвоено перед».
Идея определённого присваивания заключается в том, что присваивание локальной переменной, объявленной оператором или пустым final полем, должно произойти на каждом возможном пути выполнения до доступа. Аналогично, идея определённого неприсвоения заключается в том, что никакое другое присваивание пустой final переменной не допускается ни на каком возможном пути выполнения до присваивания.
Анализ учитывает структуру операторов и выражений; он также предоставляет специальное обращение к операторам выражений &&, ||, ! и ? :, а также к булевым константным выражениям.
За исключением специального обращения к условным булевым операторам &&, || и ? : и к булевым константным выражениям, значения выражений не учитываются при анализе потока.
Пример 16-1. Определённое присваивание учитывает структуру операторов и выражений
Компилятор Java распознаёт, что k определённо присвоено перед его доступом (в качестве аргумента вызова метода) в коде:
{
int k;
if (v > 0 && (k = System.in.read()) >= 0)
System.out.println(k);
}
потому что доступ происходит только в том случае, если значение выражения:
v > 0 && (k = System.in.read()) >= 0
равно true, и значение может быть 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.
С другой стороны, код:
{
int k;
while (n < 4) {
k = n;
if (k >= 5) break;
n = 6;
}
System.out.println(k); /* k is not "definitely assigned"
before this statement */
}
должен быть отклонен компилятором Java, потому что в этом случае оператор while не гарантируется для выполнения своего тела с точки зрения правил определённого присваивания.
Пример 16-2. Определённое присваивание не учитывает значения выражений
Компилятор Java должен сгенерировать ошибку компиляции для кода:
{
int k;
int n = 5;
if (n > 2)
k = 3;
System.out.println(k); /* k is not "definitely assigned"
before this statement */
}
даже если значение n известно на этапе компиляции, и, в принципе, на этапе компиляции может быть известно, что присваивание k всегда будет выполнено (точнее, вычислено). Компилятор Java должен действовать в соответствии с правилами, изложенными в этом разделе. Правила распознают только константные выражения; в этом примере выражение n
> 2 не является константным выражением, как определено в §15.29.
В качестве другого примера, компилятор Java примет код:
void flow(boolean flag) {
int k;
if (flag)
k = 3;
else
k = 4;
System.out.println(k);
}
с точки зрения определённого присваивания k, потому что правила, изложенные в этом разделе, позволяют ему понять, что k присвоено независимо от того, является ли flag 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 this statement */
}
и, следовательно, компиляция этой программы должна привести к возникновению ошибки компиляции.
Пример 16-3. Определённая необъявленность
Компилятор Java примет код:
void unflow(boolean flag) {
final int k;
if (flag) {
k = 3;
System.out.println(k);
}
else {
k = 4;
System.out.println(k);
}
}
поскольку правила, изложенные в этом разделе, позволяют ему определить, что k присваивается не более одного раза (на самом деле, ровно один раз), независимо от того, является ли flag true или false. Но правила не принимают вариацию:
void unflow(boolean flag) {
final int k;
if (flag) {
k = 3;
System.out.println(k);
}
if (!flag) {
k = 4;
System.out.println(k); /* k is not "definitely unassigned"
before this statement */
}
}
и поэтому компиляция этой программы должна вызвать ошибку во время компиляции.
Для точного указания всех случаев определённого присваивания, правила в этом разделе определяют несколько технических терминов:
-
является ли переменная определённо присвоенной до оператора или выражения
-
является ли переменная определённо не присвоенной до оператора или выражения
-
является ли переменная определённо присвоенной после оператора или выражения
-
является ли переменная определённо не присвоенной после оператора или выражения
Для булевых выражений последние два уточняются до четырёх случаев:
-
является ли переменная определённо присвоенной после выражения при истинности
-
является ли переменная определённо не присвоенной после выражения при истинности
-
является ли переменная определённо присвоенной после выражения при ложности
-
является ли переменная определённо не присвоенной после выражения при ложности
Здесь при истинности и при ложности относятся к значению выражения.
Например, локальная переменная k определённо получает значение после вычисления выражения:
a && ((k=m) > 5)
когда выражение является true, но не когда выражение является false (потому что если a ложно, то присваивание k не обязательно выполняется (точнее, вычисляется)).
Фраза "V определённо присвоено после X" (где V — локальная переменная, а X — оператор или выражение) означает "V определённо присвоено после X, если X завершается нормально". Если X завершается прерывисто, присваивание может не произойти, и здесь учитываются эти правила.
Парадоксальным следствием этого определения является то, что "V определённо присвоено после break;" всегда истинно! Поскольку оператор break никогда не завершается нормально, то является пустым истиной, что V получило значение, если оператор break завершается нормально.
Оператор "V определённо не присвоено после X" (где V — переменная, а X — оператор или выражение) означает "V определённо не присвоено после X, если X завершается нормально".
Ещё более парадоксальным следствием этого определения является то, что "V определённо не присвоено после break;" всегда истинно! Поскольку оператор break никогда не завершается нормально, то является пустым истиной, что V не получило значение, если оператор break завершается нормально. (В таком случае, также является пустой истиной, что луна состоит из зелёного сыра, если оператор break завершается нормально.)
В целом, существует четыре возможности для переменной V после выполнения оператора или выражения:
-
V определённо присвоено и не определённо не присвоено.
(Правила анализа потока доказывают, что присваивание V произошло.)
-
V определённо не присвоено и не определённо присвоено.
(Правила анализа потока доказывают, что присваивание V не произошло.)
-
V не определённо присвоено и не определённо не присвоено.
(Правила не могут доказать, произошло ли присваивание V или нет.)
-
V определённо присвоено и определённо не присвоено.
(Оператор или выражение не может завершиться нормально.)
Для сокращения правил используется обычное сокращение "iff", обозначающее "если и только если". Мы также используем соглашение об аббревиатурах: если правило содержит одно или несколько появлений "[un]assigned", то оно обозначает два правила, одно, где каждое появление "[un]assigned" заменено на "определённо присвоено", и одно, где каждое появление "[un]assigned" заменено на "определённо не присвоено".
Например:
-
V [un]assigned после пустого оператора iff оно [un]assigned перед пустым оператором.
должно пониматься как два правила:
-
V определённо присвоено после пустого оператора iff оно определённо присвоено перед пустым оператором.
-
V определённо не присвоено после пустого оператора iff оно определённо не присвоено перед пустым оператором.
На протяжении остальной части этой главы, если не указано иное, мы будем использовать V для обозначения локальной переменной, объявленной оператором или пустым final полем, которое находится в области видимости (§6.3). Аналогично, мы будем использовать a, b, c и e для обозначения выражений, а S и T — для обозначения операторов. Мы будем использовать фразу "a является V" для обозначения того, что a является либо простым именем переменной V, либо простым именем V, квалифицированным this (игнорируя скобки). Мы будем использовать фразу "a не является V" для обозначения отрицания "a является V".
Анализ определённой необъявленности операторов цикла представляет собой особую проблему. Рассмотрим оператор while (. Для того, чтобы определить, является ли V определённо не присвоенной в некотором подвыражении e) Se, нам необходимо определить, является ли V определённо не присвоенной перед e. Можно было бы утверждать, что по аналогии с правилом определённого присваивания (§16.2.10), V определённо не присвоено перед e iff оно определённо не присвоено перед оператором while. Однако такое правило не подходит для наших целей. Если e вычисляется как true, то оператор S будет выполнен. Позже, если V присваивается оператором S, то в последующих итерациях V уже будет присвоено при вычислении e. Согласно предложенному правилу, было бы возможно присвоить V несколько раз, что именно мы и стремились избежать, введя эти правила.
Пересмотренное правило будет таким: "V определённо не присвоено перед e iff оно определённо не присвоено перед оператором while и определённо не присвоено после S". Однако, когда мы формулируем правило для S, мы обнаруживаем: "V определённо не присвоено перед S iff оно определённо не присвоено после e при истинности". Это приводит к цикличности. По сути, V определённо не присвоено перед условием цикла e только если оно не присвоено после цикла в целом!
Мы прерываем этот порочный круг с помощью гипотетического анализа условия и тела цикла. Например, если мы предположим, что V определённо не присвоено перед e (независимо от того, действительно ли V определённо не присвоено перед e), и можем затем доказать, что V определённо не присвоено после e, то мы знаем, что e не присваивает V. Это сформулировано более формально следующим образом:
Предполагая, что V определённо не присвоено перед e, V определённо не присвоено после e.
Варианты вышеуказанного анализа используются для определения хорошо обоснованных правил определённой необъявленности для всех операторов цикла языка программирования Java.
-
V имеет [неопределённое] присваивание после любого константного выражения (§15.29), значение которого равно
true, когда ложно. -
V имеет [неопределённое] присваивание после любого константного выражения, значение которого равно
false, когда истинно. -
V имеет [неопределённое] присваивание после любого константного выражения, значение которого равно
true, когда истинно, если V имеет [неопределённое] присваивание до константного выражения. -
V имеет [неопределённое] присваивание после любого константного выражения, значение которого равно
false, когда ложно, если V имеет [неопределённое] присваивание до константного выражения. -
V имеет [неопределённое] присваивание после булева константного выражения
e, если V имеет [неопределённое] присваивание послеe, когда истинно, и V имеет [неопределённое] присваивание послеe, когда ложно.Это эквивалентно тому, что V имеет [неопределённое] присваивание после
e, если V имеет [неопределённое] присваивание передe.
Поскольку константное выражение, значение которого равно true, никогда не имеет значение false, и константное выражение, значение которого равно false, никогда не имеет значение true, первые два правила удовлетворяются вакуумно. Они полезны при анализе выражений, включающих операторы && (§16.1.2), || (§16.1.3), ! (§16.1.4) и ? : (§16.1.5).
-
V имеет [неопределённое] присваивание после
a&&b(§15.23), когда истинно, если V имеет [неопределённое] присваивание послеb, когда истинно. -
V имеет [неопределённое] присваивание после
a&&b, когда ложно, если V имеет [неопределённое] присваивание послеa, когда ложно, и V имеет [неопределённое] присваивание послеb, когда ложно. -
V имеет [неопределённое] присваивание перед
a, если V имеет [неопределённое] присваивание передa&&b. -
V имеет [неопределённое] присваивание перед
b, если V имеет [неопределённое] присваивание послеa, когда истинно. -
V имеет [неопределённое] присваивание после
a&&b, если V имеет [неопределённое] присваивание послеa&&b, когда истинно, и V имеет [неопределённое] присваивание послеa&&b, когда ложно.
-
V имеет [неопределённое] присваивание после
a||b(§15.24), когда истинно, если V имеет [неопределённое] присваивание послеa, когда истинно, и V имеет [неопределённое] присваивание послеb, когда истинно. -
V имеет [неопределённое] присваивание после
a||b, когда ложно, если V имеет [неопределённое] присваивание послеb, когда ложно. -
V имеет [неопределённое] присваивание перед
a, если V имеет [неопределённое] присваивание передa||b. -
V имеет [неопределённое] присваивание перед
b, если V имеет [неопределённое] присваивание послеa, когда ложно. -
V имеет [неопределённое] присваивание после
a||b, если V имеет [неопределённое] присваивание послеa||b, когда истинно, и V имеет [неопределённое] присваивание послеa||b, когда ложно.
-
V имеет [неопределённое] присваивание после
!a(§15.15.6), когда истинно, если V имеет [неопределённое] присваивание послеa, когда ложно. -
V имеет [неопределённое] присваивание после
!a, когда ложно, если V имеет [неопределённое] присваивание послеa, когда истинно. -
V имеет [неопределённое] присваивание перед
a, если V имеет [неопределённое] присваивание перед!a. -
V имеет [неопределённое] присваивание после
!a, если V имеет [неопределённое] присваивание после!a, когда истинно, и V имеет [неопределённое] присваивание после!a, когда ложно.Это эквивалентно тому, что V имеет [неопределённое] присваивание после
!a, если V имеет [неопределённое] присваивание послеa.
Предположим, что b и c являются булевыми выражениями.
-
V имеет [не]присвоенное значение после
a?b:c(§15.25) при истинном значении, если и только если V имеет [не]присвоенное значение послеbпри истинном значении и V имеет [не]присвоенное значение послеcпри истинном значении. -
V имеет [не]присвоенное значение после
a?b:cпри ложном значении, если и только если V имеет [не]присвоенное значение послеbпри ложном значении и V имеет [не]присвоенное значение послеcпри ложном значении. -
V имеет [не]присвоенное значение до
a, если и только если V имеет [не]присвоенное значение доa?b:c. -
V имеет [не]присвоенное значение до
b, если и только если V имеет [не]присвоенное значение послеaпри истинном значении. -
V имеет [не]присвоенное значение до
c, если и только если V имеет [не]присвоенное значение послеaпри ложном значении. -
V имеет [не]присвоенное значение после
a?b:c, если и только если V имеет [не]присвоенное значение послеa?b:cпри истинном значении и V имеет [не]присвоенное значение послеa?b:cпри ложном значении.
Предположим, что b и c являются выражениями, которые не являются булевыми.
-
V имеет [не]присвоенное значение после
a?b:c, если и только если V имеет [не]присвоенное значение послеbи V имеет [не]присвоенное значение послеc. -
V имеет [не]присвоенное значение до
a, если и только если V имеет [не]присвоенное значение доa?b:c. -
V имеет [не]присвоенное значение до
b, если и только если V имеет [не]присвоенное значение послеaпри истинном значении. -
V имеет [не]присвоенное значение до
c, если и только если V имеет [не]присвоенное значение послеaпри ложном значении.
Suppose that a switch expression (§15.28) has result expressions e1, ..., en, all of which are boolean-valued.
The following rules apply only if the switch block of the switch expression consists of switch labeled statement groups (§14.11.1):
-
V is definitely assigned after a
switchexpression when true iff for everyyieldstatement with expressione(§14.21) in the switch block that may exit theswitchexpression, V is definitely assigned afterewhen true. -
V is definitely assigned after a
switchexpression when false iff for everyyieldstatement with expressionein the switch block that may exit theswitchexpression, V is definitely assigned afterewhen false. -
V is definitely unassigned after a
switchexpression when true iff for everyyieldstatement with expressionein the switch block that may exit theswitchexpression, V is definitely unassigned before theyieldstatement and V is definitely unassigned afterewhen true. -
V is definitely unassigned after a
switchexpression when false iff for everyyieldstatement with expressionein the switch block that may exit theswitchexpression, V is definitely unassigned before theyieldstatement and V is definitely unassigned afterewhen false. -
V is [un]assigned before the selector expression iff V is [un]assigned before the
switchexpression. -
V is [un]assigned before the first statement of the first switch labeled statement group in the switch block iff V is [un]assigned after the selector expression.
-
V is [un]assigned before the first statement of any switch labeled statement group other than the first iff V is [un]assigned after the selector expression and V is [un]assigned after the preceding statement.
The following rules apply only if the switch block of the switch expression consists of switch rules (§14.11.1):
-
V is definitely assigned after a
switchexpression when true iff for every switch rule, one of the following is true:-
It introduces a switch rule expression
eand V is definitely assigned afterewhen true. -
It introduces a switch rule block B and for every
yieldstatement with expressionecontained in B that may exit theswitchexpression, V is definitely assigned afterewhen true. -
It introduces a switch rule
throwstatement.
-
-
V is definitely assigned after a
switchexpression when false iff for every switch rule, one of the following is true:-
It introduces a switch rule expression
eand V is definitely assigned afterewhen false. -
It introduces a switch rule block B and for every
yieldstatement with expressionecontained in B that may exit theswitchexpression, V is definitely assigned afterewhen false. -
It introduces a switch rule
throwstatement.
-
-
V is definitely unassigned after a
switchexpression when true iff for every switch rule, one of the following is true:-
It introduces a switch rule expression
eand V is definitely unassigned afterewhen true. -
It introduces a switch rule block B and for every
yieldstatement with expressionecontained in B that may exit theswitchexpression, V is definitely unassigned before theyieldstatement and V is definitely unassigned afterewhen true. -
It introduces a switch rule
throwstatement.
-
-
V is definitely unassigned after a
switchexpression when false iff for every switch rule, one of the following is true:-
It introduces a switch rule expression
eand V is definitely unassigned afterewhen false. -
It introduces a switch rule block B and for every
yieldstatement with expressionecontained in B that may exit theswitchexpression, V is definitely unassigned before theyieldstatement and V is definitely unassigned afterewhen false. -
It introduces a switch rule
throwstatement.
-
-
V is [un]assigned before any switch rule expression or switch rule statement in the switch block iff V is [un]assigned after the selector expression.
Suppose that a switch expression has result expressions e1, ..., en, not all of which are boolean-valued.
-
V is [un]assigned after a
switchexpression iff all of the following are true:-
V is [un]assigned before every
yieldstatement that may exit theswitchexpression. -
For each switch rule in the switch block, V is [un]assigned after the switch rule expression, switch rule block, or switch rule
throwstatement introduced by the switch rule.
-
-
V is [un]assigned before the selector expression of a
switchexpression iff V is [un]assigned before theswitchexpression. -
V is [un]assigned before the switch rule expression, switch rule block, or switch rule
throwstatement introduced by a switch rule in the switch block iff V is [un]assigned after the selector expression of theswitchexpression. -
V is [un]assigned before the first block statement of a switch labeled statement group in the switch block iff both of the following are true:
-
V is [un]assigned after the selector expression of the
switchexpression. -
If the switch labeled statement group is not the first in the switch block, V is [un]assigned after the last block statement of the preceding switch labeled statement group.
-
-
V is [un]assigned before a block statement that is not the first of a switch labeled statement group in the switch block iff V is [un]assigned after the preceding block statement.
The following rule applies to all switch expressions:
-
V is [un]assigned before any guard associated with the switch block of a
switchexpression iff V is [un]assigned after the selector expression.
Предположим, что e — это выражение типа boolean и не является выражением булевой константы, логическим отрицанием !a, выражением условного И a && b, выражением условного ИЛИ a || b или условным выражением a ? b : c.
-
V считается [не]назначенным после
e, когда истинно, если и только если V считается [не]назначенным послеe. -
V считается [не]назначенным после
e, когда ложно, если и только если V считается [не]назначенным послеe.
Рассмотрим выражение присваивания a = b, a += b, a -= b, a *= b, a /= b, a %= b, a <<= b, a >>= b, a >>>= b, a &= b, a |= b или a ^= b (§15.26).
-
V определённо назначено после выражения присваивания, если выполняется одно из условий:
-
aравно V, или -
V определённо назначено после
b.
-
-
V определённо не назначено после выражения присваивания, если
aне равно V и V определённо не назначено послеb. -
V [не]назначено до
a, если V [не]назначено до выражения присваивания. -
V [не]назначено до
b, если V [не]назначено послеa.
Обратите внимание, что если a равно V и V не определённо назначено до составного присваивания, такого как a &= b, то неизбежно произойдёт ошибка времени компиляции. Первое правило для определённого назначения включает дизъюнкцию «a равно V» даже для выражений составного присваивания, а не только простых присваиваний, чтобы V считалось определённо назначенным в более поздних точках кода. Включение дизъюнкции «a равно V» не влияет на двоичное решение о том, является ли программа приемлемой или приведёт к ошибке времени компиляции, но влияет на то, сколько различных точек кода можно рассматривать как ошибочные, и поэтому на практике может улучшить качество отчёта об ошибках. Аналогичное замечание относится к включению конъюнкции «a не равно V» в первое правило для определённого неназначения, указанное выше.
-
V определённо назначено после
++a(§15.15.1),--a(§15.15.2),a++(§15.14.2) илиa--(§15.14.3), если либоaравно V, либо V определённо назначено после выражения операнда. -
V определённо не назначено после
++a,--a,a++илиa--, еслиaне равно V и V определённо не назначено после выражения операнда. -
V [не]назначено до
a, если V [не]назначено до++a,--a,a++илиa--.
Если выражение не является булевым константным выражением, и не является выражением прединкремента ++a, постдекремента --a, пост-инкремента a++, постдекремента a--, выражением логического отрицания !a, выражением условного И a && b, выражением условного ИЛИ a || b, условным выражением a ? b : c, выражением присваивания или лямбда-выражением, то применяются следующие правила:
-
Если выражение не содержит подвыражений, V присваивается (не присваивается) после выражения тогда и только тогда, когда V присваивалось (не присваивалось) до выражения.
Этот случай относится к литералам, именам,
this(как квалифицированным, так и неквалифицированным), выражениям создания экземпляра класса без аргументов, выражениям создания массивов с инициализаторами, не содержащими выражений, выражениям доступа к полям суперкласса, выражениям вызова методов без аргументов (неквалифицированным и квалифицированным типом), выражениям вызова методов суперкласса без аргументов, а также выражениям ссылки на метод суперкласса и квалифицированным по типу. -
Если выражение содержит подвыражения, V присваивается (не присваивается) после выражения тогда и только тогда, когда V присваивается (не присваивается) после его правого ближайшего подвыражения.
Существует тонкое обоснование утверждения, что переменная V может быть определенно не присвоена после выражения вызова метода. Само по себе, без оговорок, это утверждение не всегда верно, так как вызываемый метод может выполнять присваивания. Но следует помнить, что в целях языка программирования Java понятие определенного неприсваивания применяется только к пустым final переменным. Если V — пустая final локальная переменная, то только метод, которому принадлежит её объявление, может выполнять присваивания V. Если V — пустое final поле, то только конструктор или инициализатор класса, содержащий объявление V, может выполнять присваивания V; ни один метод не может выполнять присваивания V. Наконец, явные вызовы конструкторов (§8.8.7.1) обрабатываются особым образом (§16.9); хотя они синтаксически похожи на операторы выражений, содержащие вызовы методов, они не являются операторами выражений, и поэтому правила этой секции не применяются к явным вызовам конструкторов.
Если выражение является лямбда-выражением, то применяются следующие правила:
-
V присваивается (не присваивается) после выражения тогда и только тогда, когда V присваивалось (не присваивалось) до выражения.
-
V определенно присвоено до выражения или блока, который является телом лямбды (§15.27.2) тогда и только тогда, когда V определенно присвоено до лямбда-выражения.
Ни одно правило не позволяет переменной V быть определенно неприсвоенной перед телом лямбды. Это сделано намеренно: переменная, которая была определенно неприсвоена перед телом лямбды, может оказаться присвоенной позже, поэтому мы не можем сделать вывод, что переменная будет неприсвоена при выполнении тела.
Для любого непосредственного подвыражения y выражения x, где x не является лямбда-выражением, V присваивается (не присваивается) до y, если выполняется одно из следующих условий:
-
y— самое левое непосредственное подвыражениеxи V присваивается (не присваивается) доx. -
y— правое операнд бинарного оператора и V присваивается (не присваивается) после левого операнда. -
x— обращение к элементу массива,y— подвыражение в скобках, и V присваивается (не присваивается) после подвыражения перед скобками. -
x— выражение вызова метода,y— первое выражение аргумента в выражении вызова метода, и V присваивается (не присваивается) после основного выражения, вычисляющего целевой объект. -
x— выражение вызова метода или выражение создания экземпляра класса;y— выражение аргумента, но не первое; и V присваивается (не присваивается) после выражения аргумента слева отy. -
x— квалифицированное выражение создания экземпляра класса,y— первое выражение аргумента в выражении создания экземпляра класса, и V присваивается (не присваивается) после основного выражения, вычисляющего квалифицируемый объект. -
x— выражение создания массива;y— выражение измерения, но не первое; и V присваивается (не присваивается) после выражения измерения слева отy. -
x— выражение создания массива, инициализированное через инициализатор массива;y— инициализатор массива вx; и V присваивается (не присваивается) после выражения измерения слева отy.
-
V является [не]присвоенным после пустого оператора (§14.6) тогда и только тогда, когда он [не]присвоен до пустого оператора.
-
Пустое
finalполе-член V определённо присвоено (и, более того, не определённо не присвоено) до блока (§14.2), который является телом любого метода в области видимости V, и перед объявлением любого класса, объявленного в области видимости V. -
Локальная переменная V, объявленная оператором S, определённо не присвоена (и, более того, не определённо присвоена) перед блоком, который является телом конструктора, метода, инициализатора экземпляра или статического инициализатора, содержащего S.
-
Пусть C — класс, объявленный в области видимости V. Тогда V определённо присвоено перед блоком, который является телом любого конструктора, метода, инициализатора экземпляра или статического инициализатора, объявленного в C, тогда и только тогда, когда V определённо присвоено перед объявлением C.
Обратите внимание, что нет правил, позволяющих сделать вывод о том, что V определённо не присвоено перед блоком, который является телом любого конструктора, метода, инициализатора экземпляра или статического инициализатора, объявленного в C. Мы можем неформально сделать вывод о том, что V не является определённо не присвоенным перед блоком, который является телом любого конструктора, метода, инициализатора экземпляра или статического инициализатора, объявленного в C, но нет необходимости явно формулировать такое правило.
-
V является [не]присвоенным после пустого блока, если V является [не]присвоенным перед пустым блоком.
-
V является [не]присвоенным после непустого блока, если V является [не]присвоенным после последнего оператора в блоке.
-
V является [не]присвоенным перед первым оператором блока, если V является [не]присвоенным перед блоком.
-
V является [не]присвоенным перед любым другим оператором S блока, если V является [не]присвоенным после оператора, непосредственно предшествующего S в блоке.
Мы говорим, что V определённо не присвоено повсюду в блоке B, если:
-
V определённо не присвоено перед B.
-
V определённо присвоено после
eв каждом выражении присваивания V=e, V+=e, V-=e, V*=e, V/=e, V%=e, V<<=e, V>>=e, V>>>=e, V&=e, V|=eили V^=e, которое встречается в B. -
V определённо присвоено перед каждым выражением
++V,--V, V++или V--, которое встречается в B.
Эти условия интуитивно не понятны и требуют некоторого объяснения. Рассмотрим простое присваивание V = e. Если V определённо присвоено после e, то либо:
-
Присваивание происходит в мёртвом коде, и V неопределённо определено. В этом случае присваивание фактически не произойдёт, и мы можем предположить, что V не присваивается выражением присваивания. Или:
-
V уже было присвоено более ранним выражением до
e. В этом случае текущее присваивание вызовет ошибку времени компиляции.
Таким образом, мы можем заключить, что если условия выполняются программой, не вызывающей ошибки времени компиляции, то любые присваивания V в B фактически не будут выполняться во время выполнения.
-
V является [не]присвоенным после объявления локального класса или интерфейса (§14.3), если V является [не]присвоенным до объявления локального класса или интерфейса.
-
V является [не]присвоенным после оператора объявления локальной переменной, не содержащего инициализаторов переменных, если V является [не]присвоенным до оператора объявления локальной переменной.
-
V определённо присвоено после оператора объявления локальной переменной, содержащего по крайней мере один инициализатор переменной, если либо V определённо присвоено после последнего инициализатора переменной в операторе объявления локальной переменной, либо последний инициализатор переменной в объявлении находится в деклараторе, объявляющем V.
-
V определённо не присвоено после оператора объявления локальной переменной, содержащего по крайней мере один инициализатор переменной, если V определённо не присвоено после последнего инициализатора переменной в операторе объявления локальной переменной, и последний инициализатор переменной в объявлении не находится в деклараторе, объявляющем V.
-
V является [не]присвоенным перед первым инициализатором переменной в операторе объявления локальной переменной, если V является [не]присвоенным перед оператором объявления локальной переменной.
-
V определённо присвоено перед любым инициализатором переменной
e, кроме первого, в операторе объявления локальной переменной, если либо V определённо присвоено после инициализатора переменной слева отe, либо выражение инициализатора слева отeнаходится в деклараторе, объявляющем V. -
V определённо не присвоено перед любым инициализатором переменной
e, кроме первого, в операторе объявления локальной переменной, если V определённо не присвоено после инициализатора переменной слева отeи выражение инициализатора слева отeне находится в деклараторе, объявляющем V.
-
V является [не]присвоенным после оператора с меткой
L:S (гдеL— метка) (§14.7), если V является [не]присвоенным после S и V является [не]присвоенным перед каждым операторомbreak, который может завершить оператор с меткойL:S. -
V является [не]присвоенным перед S, если V является [не]присвоенным перед
L:S.
-
V присваивается/не присваивается после оператора выражения
e;(§14.8) тогда и только тогда, когда он присваивается/не присваивается послеe. -
V присваивается/не присваивается перед
eтогда и только тогда, когда он присваивается/не присваивается передe;.
Следующие правила применяются к оператору if if ( (§14.9.1): e) S
-
V присваивается/не присваивается после
if (тогда и только тогда, когда V присваивается/не присваивается после S и V присваивается/не присваивается послеe) Seпри ложном условии. -
V присваивается/не присваивается перед
eтогда и только тогда, когда V присваивается/не присваивается передif (.e) S -
V присваивается/не присваивается перед S тогда и только тогда, когда V присваивается/не присваивается после
eпри истинном условии.
Следующие правила применяются к оператору if-then-else if (e) S else
T (§14.9.2):
-
V присваивается/не присваивается после
if (тогда и только тогда, когда V присваивается/не присваивается после S и V присваивается/не присваивается после T.e) S else T -
V присваивается/не присваивается перед
eтогда и только тогда, когда V присваивается/не присваивается передif (.e) S else T -
V присваивается/не присваивается перед S тогда и только тогда, когда V присваивается/не присваивается после
eпри истинном условии. -
V присваивается/не присваивается перед T тогда и только тогда, когда V присваивается/не присваивается после
eпри ложном условии.
Следующие правила применяются как к оператору assert
, так и к оператору e1assert (§14.10): e1 :
e2
-
V присваивается/не присваивается перед
e1тогда и только тогда, когда V присваивается/не присваивается перед операторомassert. -
V однозначно присваивается после оператора
assertтогда и только тогда, когда V однозначно присваивается перед операторомassert. -
V однозначно не присваивается после оператора
assertтогда и только тогда, когда V однозначно не присваивается перед операторомassertи V однозначно не присваивается послеe1при истинном условии.
Следующее правило применяется к оператору assert : e1 : e2
-
V присваивается/не присваивается перед
e2тогда и только тогда, когда V присваивается/не присваивается послеe1при ложном условии.
-
V присваивается/не присваивается после оператора
switch(§14.11) тогда и только тогда, когда все следующие утверждения истинны:-
V присваивается/не присваивается перед каждым оператором
break(§14.15), который может завершить операторswitch. -
Для каждого правила switch (§14.11.1) в блоке switch, V присваивается/не присваивается после выражения switch-правила, блока switch-правила или оператора switch-правила
throw, введённого switch-правилом. -
Если в блоке switch есть группа операторов с меткой switch, то V присваивается/не присваивается после последнего оператора блока последней группы операторов с меткой switch.
-
Если оператор
switchне является исчерпывающим (§14.11.1.1), или если блок switch заканчивается меткой switch, за которой следует разделитель}, то V присваивается/не присваивается после выражения селектора.
-
-
V присваивается/не присваивается перед выражением селектора оператора
switchтогда и только тогда, когда V присваивается/не присваивается перед операторомswitch. -
V присваивается/не присваивается перед любым условием, связанным с блоком switch оператора
switch, тогда и только тогда, когда V присваивается/не присваивается после выражения селектора. -
V присваивается/не присваивается перед выражением switch-правила, блоком switch-правила или оператором switch-правила
throw, введённым switch-правилом в блоке switch, тогда и только тогда, когда V присваивается/не присваивается после выражения селектора оператораswitch. -
V присваивается/не присваивается перед первым оператором блока группы операторов с меткой switch в блоке switch тогда и только тогда, когда оба следующих утверждения истинны:
-
V присваивается/не присваивается после выражения селектора оператора
switch. -
Если группа операторов с меткой switch не является первой в блоке switch, то V присваивается/не присваивается после последнего оператора блока предыдущей группы операторов с меткой switch.
-
-
V присваивается/не присваивается перед оператором блока, который не является первым в группе операторов с меткой switch в блоке switch, тогда и только тогда, когда V присваивается/не присваивается после предыдущего оператора блока.
-
V присваивается/не присваивается после оператора
while ((§14.12) тогда и только тогда, когда V присваивается/не присваивается послеe) Seпри ложном условии и V присваивается/не присваивается перед каждым операторомbreak, для которого операторwhileявляется целью break. -
V однозначно присваивается перед
eтогда и только тогда, когда V однозначно присваивается перед операторомwhile. -
V однозначно не присваивается перед
eтогда и только тогда, когда все следующие утверждения истинны:-
V однозначно не присваивается перед оператором
while. -
Предполагая, что V однозначно не присваивается перед
e, V однозначно не присваивается после S. -
Предполагая, что V однозначно не присваивается перед
e, V однозначно не присваивается перед каждым операторомcontinue, для которого операторwhileявляется целью continue.
-
-
V присваивается/не присваивается перед S тогда и только тогда, когда V присваивается/не присваивается после
eпри истинном условии.
-
V [присвоено/не присвоено] после
do S while ((§14.13) тогда и только тогда, когда V [присвоено/не присвоено] послеe);e, когда ложно, и V [присвоено/не присвоено] перед каждым операторомbreak, для которого операторdoявляется целевым оператором break. -
V определённо присвоено перед S тогда и только тогда, когда V определённо присвоено перед оператором
do. -
V определённо не присвоено перед S, если все следующие условия истинны:
-
V определённо не присвоено перед оператором
do. -
Предполагая, что V определённо не присвоено перед S, V определённо не присвоено после
e, когда истинно.
-
-
V [присвоено/не присвоено] перед
eтогда и только тогда, когда V [присвоено/не присвоено] после S и V [присвоено/не присвоено] перед каждым операторомcontinue, для которого операторdoявляется целевым оператором continue.
Здесь приведены правила для основного оператора for (§14.14.1). Поскольку расширенный оператор for (§14.14.2) определяется путём трансляции в базовый оператор for, для него нет необходимости в особых правилах.
-
V [присвоено/не присвоено] после оператора
forтогда и только тогда, когда оба следующих условия истинны:-
Или выражение условия отсутствует, или V [присвоено/не присвоено] после выражения условия, когда оно ложно.
-
V [присвоено/не присвоено] перед каждым оператором
break, для которого операторforявляется целевым оператором break.
-
-
V [присвоено/не присвоено] перед частью инициализации оператора
forтогда и только тогда, когда V [присвоено/не присвоено] перед операторомfor. -
V определённо присвоено перед частью условия оператора
forтогда и только тогда, когда V определённо присвоено после части инициализации оператораfor. -
V определённо не присвоено перед частью условия оператора
for, если оба следующих условия истинны:-
V определённо не присвоено после части инициализации оператора
for. -
Предполагая, что V определённо не присвоено перед частью условия оператора
for, V определённо не присвоено после части инкрементации оператораfor.
-
-
V [присвоено/не присвоено] перед вложенным оператором, если выполняется любое из следующих условий:
-
Выражение условия присутствует и V [присвоено/не присвоено] после выражения условия, когда оно истинно.
-
Выражение условия отсутствует и V [присвоено/не присвоено] перед частью условия оператора
for.
-
-
V [присвоено/не присвоено] перед частью инкрементации оператора
for, если V [присвоено/не присвоено] после вложенного оператора и V [присвоено/не присвоено] перед каждым операторомcontinue, для которого операторforявляется целевым оператором continue.
-
Если часть инициализации оператора
forпредставляет собой оператор объявления локальной переменной, применяются правила из §16.2.4. -
В противном случае, если часть инициализации пуста, то V [присвоено/не присвоено] после части инициализации тогда и только тогда, когда V [присвоено/не присвоено] перед частью инициализации.
-
В противном случае применяются три правила:
-
V [присвоено/не присвоено] после части инициализации тогда и только тогда, когда V [присвоено/не присвоено] после последнего оператора выражения в части инициализации.
-
V [присвоено/не присвоено] перед первым оператором выражения в части инициализации тогда и только тогда, когда V [присвоено/не присвоено] перед частью инициализации.
-
V [присвоено/не присвоено] перед оператором выражения S, отличным от первого в части инициализации, тогда и только тогда, когда V [присвоено/не присвоено] после оператора выражения, непосредственно предшествующего S.
-
-
Если часть инкрементации оператора
forпуста, то V [присвоено/не присвоено] после части инкрементации тогда и только тогда, когда V [присвоено/не присвоено] перед частью инкрементации. -
В противном случае применяются три правила:
-
V [присвоено/не присвоено] после части инкрементации тогда и только тогда, когда V [присвоено/не присвоено] после последнего оператора выражения в части инкрементации.
-
V [присвоено/не присвоено] перед первым оператором выражения в части инкрементации тогда и только тогда, когда V [присвоено/не присвоено] перед частью инкрементации.
-
V [присвоено/не присвоено] перед оператором выражения S, отличным от первого в части инкрементации, тогда и только тогда, когда V [присвоено/не присвоено] после оператора выражения, непосредственно предшествующего S.
-
-
По соглашению, мы говорим, что V [присвоено/не присвоено] после любого оператора
break,yield,continue,returnилиthrow(§14.15, §14.21, §14.16, §14.17, §14.18).Понятие, что переменная "[присвоено/не присвоено] после" оператора или выражения, на самом деле означает "является [присвоено/не присвоено] после завершения оператора или выражения в нормальном режиме". Поскольку оператор
break,yield,continue,returnилиthrowникогда не завершается в нормальном режиме, он тривиально удовлетворяет этому понятию. -
В операторе
yieldс выражениемe, или оператореreturnс выражениемe, или оператореthrowс выражениемe, V [присвоено/не присвоено] передeтогда и только тогда, когда V [присвоено/не присвоено] перед операторомyield,returnилиthrow.
-
V присвоено/не присвоено после
synchronized ((§14.19) тогда и только тогда, когда V присвоено/не присвоено после S.e) S -
V присвоено/не присвоено до
eтогда и только тогда, когда V присвоено/не присвоено до оператораsynchronized (.e) S -
V присвоено/не присвоено до S тогда и только тогда, когда V присвоено/не присвоено после
e.
Правила в данной области описывают управляющие структуры try-catch и try-catch-finally (§14.20.1, §14.20.2). Так как управляющая структура try-with-resources (§14.20.3) определяется переводом в управляющую структуру try-catch-finally, для нее нет необходимости предоставлять специальные правила.
Данные правила применяются ко всем управляющим структурам try (§14.20), вне зависимости от наличия блока finally:
-
V присвоено/не присвоено до блока
tryтогда и только тогда, когда V присвоено/не присвоено до управляющей структурыtry. -
V определённо присвоено до блока
catchтогда и только тогда, когда V определённо присвоено до блокаtry. -
V определённо не присвоено до блока
catch, если все следующие условия истинны:-
V определённо не присвоено после блока
try. -
V определённо не присвоено перед каждым оператором
return, принадлежащим блокуtry. -
V определённо не присвоено после
eв каждом операторе видаthrowe, принадлежащем блокуtry. -
V определённо не присвоено после каждого оператора
assert, находящегося в блокеtry. -
V определённо не присвоено перед каждым оператором
break, принадлежащим блокуtryи в котором целевой оператор break содержит (или равен) операторуtry. -
V определённо не присвоено перед каждым оператором
continue, принадлежащим блокуtryи в котором целевой оператор continue содержит операторtry.
-
Если в операторе try нет блока finally, то это правило также применяется:
-
V присвоено/не присвоено после оператора
tryтогда и только тогда, когда V присвоено/не присвоено после блокаtryи V присвоено/не присвоено после каждого блокаcatchв оператореtry.
Если оператор try имеет блок finally, то эти правила также применяются:
-
V определённо присвоено после оператора
try, если истинно хотя бы одно из следующих утверждений:-
V определённо присвоено после блока
tryи V определённо присвоено после каждого блокаcatchв оператореtry. -
V определённо присвоено после блока
finally.
-
-
V определённо не присвоено после оператора
tryтогда и только тогда, когда V определённо не присвоено после блокаfinally. -
V определённо присвоено до блока
finallyтогда и только тогда, когда V определённо присвоено до оператораtry. -
V определённо не присвоено до блока
finally, если все следующие условия истинны:-
V определённо не присвоено после блока
try. -
V определённо не присвоено перед каждым оператором
return, принадлежащим блокуtry. -
V определённо не присвоено после
eв каждом операторе видаthrowe, принадлежащем блокуtry. -
V определённо не присвоено после каждого оператора
assert, находящегося в блокеtry. -
V определённо не присвоено перед каждым оператором
break, принадлежащим блокуtryи в котором целевой оператор break содержит (или равен) операторуtry. -
V определённо не присвоено перед каждым оператором
continue, принадлежащим блокуtryи в котором целевой оператор continue содержит операторtry. -
V определённо не присвоено после каждого блока
catchоператораtry.
-
-
V присвоено/не присвоено после пустого инициализатора массива (§10.6) тогда и только тогда, когда V присвоено/не присвоено перед пустым инициализатором.
-
V присвоено/не присвоено после непустого инициализатора массива тогда и только тогда, когда V присвоено/не присвоено после последнего инициализатора переменной в инициализаторе.
-
V присвоено/не присвоено перед первым инициализатором переменной инициализатора массива тогда и только тогда, когда V присвоено/не присвоено перед инициализатором массива.
-
V присвоено/не присвоено перед любым другим инициализатором переменной
eинициализатора массива тогда и только тогда, когда V присвоено/не присвоено после инициализатора переменной слева отeв инициализаторе массива.
Правила, определяющие, когда переменная определённо инициализирована или определённо не инициализирована перед константой перечисления (§8.9.1), приведены в §16.8.
Это связано с тем, что константа перечисления по сути является static final полем (§8.3.1.1, §8.3.1.2), которая инициализируется выражением создания экземпляра класса (§15.9).
-
V определённо инициализирована перед объявлением тела класса константы перечисления без аргументов, объявленной в области видимости V, если V определённо инициализирована перед константой перечисления.
-
V определённо инициализирована перед объявлением тела класса константы перечисления с аргументами, объявленной в области видимости V, если V определённо инициализирована после последнего выражения аргумента константы перечисления.
Статус определённой инициализации/неинициализации любого конструкта внутри тела класса константы перечисления регулируется обычными правилами для классов.
-
V [не]инициализирована перед первым аргументом константы перечисления, если она [не]инициализирована перед константой перечисления.
-
V [не]инициализирована перед
y(аргументом константы перечисления, но не первым), если V [не]инициализирована после аргумента слева отy.
-
V определённо инициализирована перед объявлением анонимного класса (§15.9.5), объявленного в области видимости V, если V определённо инициализирована после выражения создания экземпляра класса, объявляющего анонимный класс.
Должно быть ясно, что если анонимный класс неявно определён константой перечисления, применяются правила §16.5.
Пусть C — класс, а V — пустое final поле C. Тогда:
Пусть C — класс, объявленный в области видимости V. Тогда:
-
V определённо инициализирована перед объявлением вложенного класса или интерфейса C, если V определённо инициализирована перед объявлением C.
Пусть C — класс, объявленный в области видимости V. Тогда:
-
V определённо инициализирована перед константой перечисления (§8.9.1) или статическим инициализатором переменной (§8.3.2) C, если V определённо инициализирована перед объявлением C.
Обратите внимание, что нет правил, которые позволили бы нам заключить, что V определённо не инициализирована перед статическим инициализатором переменной или константой перечисления. Мы можем неофициально заключить, что V не определённо не инициализирована перед каким-либо статическим инициализатором переменной C, но нет необходимости формулировать такое правило явно.
Пусть C — класс, а V — пустое static final поле-член C, объявленное в C. Тогда:
-
V определённо не инициализирована (и, более того, не определённо инициализирована) перед самым левым константой перечисления, статическим инициализатором (§8.7) или статическим инициализатором переменной C.
-
V [не]инициализирована перед константой перечисления, статическим инициализатором или статическим инициализатором переменной C (кроме самого левого), если V [не]инициализирована после предыдущей константы перечисления, статического инициализатора или статического инициализатора переменной C.
Пусть C — класс, а V — пустое static final поле-член C, объявленное в родительском классе C. Тогда:
-
V определённо инициализирована (и, более того, не определённо не инициализирована) перед каждой константой перечисления C.
-
V определённо инициализирована (и, более того, не определённо не инициализирована) перед блоком, являющимся телом статического инициализатора C.
-
V определённо инициализирована (и, более того, не определённо не инициализирована) перед каждым статическим инициализатором переменной C.
Пусть C — класс, объявленный в области видимости V. Тогда:
-
V определённо инициализирован перед инициализатором переменной экземпляра (§8.3.2) класса C тогда и только тогда, когда V определённо инициализирован перед объявлением C.
Обратите внимание, что нет правил, которые позволили бы нам сделать вывод, что V определённо не инициализирован перед инициализатором переменной экземпляра. Мы можем неофициально сделать вывод, что V не определённо не инициализирован перед любым инициализатором переменной экземпляра класса C, но нет необходимости явно формулировать такое правило.
Пусть C — класс, а V — пустое final не-static поле члена класса C, объявленное в C. Тогда:
-
V определённо не инициализирован (и, более того, не определённо инициализирован) перед самым левым инициализатором экземпляра (§8.6) или инициализатором переменной экземпляра класса C.
-
V [не]инициализирован перед инициализатором экземпляра или инициализатором переменной экземпляра класса C, отличным от левого, если V [не]инициализирован после предшествующего инициализатора экземпляра или инициализатора переменной экземпляра класса C.
Следующие правила действуют внутри конструкторов (§8.8.7) класса C:
-
V определённо инициализирован (и, более того, не определённо не инициализирован) после вызова альтернативного конструктора (§8.8.7.1).
-
V определённо не инициализирован (и, более того, не определённо инициализирован) перед явным или неявным вызовом конструктора суперкласса (§8.8.7.1).
-
Если у класса C нет инициализаторов экземпляров или инициализаторов переменных экземпляров, то V не определённо инициализирован (и, более того, определённо не инициализирован) после явного или неявного вызова конструктора суперкласса.
-
Если у класса C есть хотя бы один инициализатор экземпляра или инициализатор переменной экземпляра, то V [не]инициализирован после явного или неявного вызова конструктора суперкласса тогда и только тогда, когда V [не]инициализирован после самого правого инициализатора экземпляра или инициализатора переменной экземпляра класса C.
Пусть C — класс, а V — пустое final поле члена класса C, объявленное в суперклассе C. Тогда:
-
V определённо инициализирован (и, более того, не определённо не инициализирован) перед блоком, который является телом конструктора или инициализатора экземпляра класса C.
-
V определённо инициализирован (и, более того, не определённо не инициализирован) перед каждым инициализатором переменной экземпляра класса C.
© Oracle and/or its affiliates. All rights reserved.
Licensed under the Oracle Technology Network License Agreement.