Глава 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», означающее «если и только если». Мы также используем соглашение об аббревиатуре: если правило содержит одну или несколько вхождений "[не]инициализирован", то оно обозначает два правила, одно с заменой каждого вхождения "[не]инициализирован" на «определённо инициализирован», а другое с заменой каждого вхождения "[не]инициализирован" на «определённо неинициализирован».
Например:
-
V [не]инициализировано после пустого оператора iff оно [не]инициализировано перед пустым оператором.
должно пониматься как два правила:
-
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.
END_OF_DOCUMENT_MARKER-
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при ложном значении.
Предположим, что выражение switch (§15.28) имеет выражения результата e1, ..., en, все из которых имеют логические значения.
Следующие правила применяются только в том случае, если блок switch выражения switch состоит из групп операторов switch с метками (§14.11.1):
-
V определенно присваивается после выражения
switch, когда истинно, если для каждого оператораyieldс выражениемe(§14.21) в блоке switch, который может выйти из выраженияswitch, V определенно присваивается послеe, когда истинно. -
V определенно присваивается после выражения
switch, когда ложно, если для каждого оператораyieldс выражениемeв блоке switch, который может выйти из выраженияswitch, V определенно присваивается послеe, когда ложно. -
V определенно не присваивается после выражения
switch, когда истинно, если для каждого оператораyieldс выражениемeв блоке switch, который может выйти из выраженияswitch, V определенно не присваивается перед операторомyieldи V определенно не присваивается послеe, когда истинно. -
V определенно не присваивается после выражения
switch, когда ложно, если для каждого оператораyieldс выражениемeв блоке switch, который может выйти из выраженияswitch, V определенно не присваивается перед операторомyieldи V определенно не присваивается послеe, когда ложно. -
V [не]присваивается перед выражением выбора, если V [не]присваивается перед выражением
switch. -
V [не]присваивается перед первым оператором первой группы операторов switch с метками в блоке switch, если V [не]присваивается после выражения выбора.
-
V [не]присваивается перед первым оператором любой группы операторов switch с метками, отличной от первой, если V [не]присваивается после выражения выбора и V [не]присваивается после предыдущего оператора.
Следующие правила применяются только в том случае, если блок switch выражения switch состоит из правил switch (§14.11.1):
-
V определенно присваивается после выражения
switch, когда истинно, если для каждого правила switch истинно одно из следующих утверждений:-
Оно вводит выражение правила switch
e, и V определенно присваивается послеe, когда истинно. -
Оно вводит блок правила switch B, и для каждого оператора
yieldс выражениемe, содержащимся в B, который может выйти из выраженияswitch, V определенно присваивается послеe, когда истинно. -
Оно вводит оператор
throwправила switch.
-
-
V определенно присваивается после выражения
switch, когда ложно, если для каждого правила switch истинно одно из следующих утверждений:-
Оно вводит выражение правила switch
e, и V определенно присваивается послеe, когда ложно. -
Оно вводит блок правила switch B, и для каждого оператора
yieldс выражениемe, содержащимся в B, который может выйти из выраженияswitch, V определенно присваивается послеe, когда ложно. -
Оно вводит оператор
throwправила switch.
-
-
V определенно не присваивается после выражения
switch, когда истинно, если для каждого правила switch истинно одно из следующих утверждений:-
Оно вводит выражение правила switch
e, и V определенно не присваивается послеe, когда истинно. -
Оно вводит блок правила switch B, и для каждого оператора
yieldс выражениемe, содержащимся в B, который может выйти из выраженияswitch, V определенно не присваивается перед операторомyieldи V определенно не присваивается послеe, когда истинно. -
Оно вводит оператор
throwправила switch.
-
-
V определенно не присваивается после выражения
switch, когда ложно, если для каждого правила switch истинно одно из следующих утверждений:-
Оно вводит выражение правила switch
e, и V определенно не присваивается послеe, когда ложно. -
Оно вводит блок правила switch B, и для каждого оператора
yieldс выражениемe, содержащимся в B, который может выйти из выраженияswitch, V определенно не присваивается перед операторомyieldи V определенно не присваивается послеe, когда ложно. -
Оно вводит оператор
throwправила switch.
-
-
V [не]присваивается перед любым выражением правила switch или оператором правила switch в блоке switch, если V [не]присваивается после выражения выбора.
Предположим, что выражение switch имеет выражения результата e1, ..., en, не все из которых имеют логические значения.
-
V [не]присваивается после выражения
switch, если истинны все следующие утверждения:-
V [не]присваивается перед каждым оператором
yield, который может выйти из выраженияswitch. -
Для каждого правила switch в блоке switch V [не]присваивается после выражения правила switch, блока правила switch или оператора
throwправила switch, введенного правилом switch.
-
-
V [не]присваивается перед выражением выбора выражения
switch, если V [не]присваивается перед выражениемswitch. -
V [не]присваивается перед выражением правила switch, блоком правила switch или оператором
throwправила switch, введенным правилом switch в блоке switch, если V [не]присваивается после выражения выбора выраженияswitch. -
V [не]присваивается перед первым оператором блока группы операторов switch с метками в блоке switch, если истинны оба следующих утверждения:
-
V [не]присваивается после выражения выбора выражения
switch. -
Если группа операторов switch с метками не является первой в блоке switch, V [не]присваивается после последнего оператора блока предыдущей группы операторов switch с метками.
-
-
V [не]присваивается перед оператором блока, который не является первым в группе операторов switch с метками в блоке switch, если V [не]присваивается после предыдущего оператора блока.
Следующее правило применяется ко всем выражениям switch:
-
V [не]присваивается перед любой защитой, связанной с блоком switch выражения
switch, если V [не]присваивается после выражения выбора.
Предположим, что 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, условным выражением AND a && b, условным выражением OR 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) тогда и только тогда, когда оно [имеет] присвоение до пустого оператора.
-
Поле-член 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 ( (§14.9.1): e) S
-
V имеет [не]присвоенное значение после
if (тогда и только тогда, когда V имеет [не]присвоенное значение после S и V имеет [не]присвоенное значение послеe) Seпри ложном условии. -
V имеет [не]присвоенное значение перед
eтогда и только тогда, когда V имеет [не]присвоенное значение передif (.e) S -
V имеет [не]присвоенное значение перед S тогда и только тогда, когда V имеет [не]присвоенное значение после
eпри истинном условии.
Следующие правила применяются к оператору 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 с ресурсами (§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 метода или конструктора (§8.4.1, §8.8.1) определённо присваивается (и, более того, не определённо не присваивается) перед телом метода или конструктора.
-
Параметр исключения V блока
catch(§14.20) определённо присваивается (и, более того, не определённо не присваивается) перед телом блокаcatch.
-
V имеет [не]присвоенное значение после пустого инициализатора массива (§10.6) тогда и только тогда, когда V имеет [не]присвоенное значение до пустого инициализатора массива.
-
V имеет [не]присвоенное значение после непустого инициализатора массива тогда и только тогда, когда V имеет [не]присвоенное значение после последнего инициализатора переменной в инициализаторе массива.
-
V имеет [не]присвоенное значение перед первым инициализатором переменной в инициализаторе массива тогда и только тогда, когда V имеет [не]присвоенное значение перед инициализатором массива.
-
V имеет [не]присвоенное значение перед любым другим инициализатором переменной
eинициализатора массива тогда и только тогда, когда V имеет [не]присвоенное значение после инициализатора переменной слева отeв инициализаторе массива.
Правила, определяющие, когда переменная определённо инициализирована или определённо не инициализирована перед константой перечисления (§8.9.1), приведены в §16.8.
Это связано с тем, что константа перечисления по существу является static static полем (§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.