Глава 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).
Для каждого доступа к локальной переменной или пустому final полю x, x должно быть определённо присвоено до доступа, иначе возникает ошибка компиляции.
Аналогично, каждая пустая final переменная должна быть присвоена не более одного раза; она должна быть определённо не присвоена при выполнении присваивания.
Такое присваивание определено тогда и только тогда, когда простое имя переменной (или, для поля, его простое имя, квалифицированное this) появляется в левой части оператора присваивания.
Для каждого присваивания пустой final переменной, переменная должна быть определённо не присвоена перед присваиванием, иначе возникает ошибка компиляции.
Остальная часть этой главы посвящена точному объяснению терминов «определённо присвоено до» и «определённо не присвоено до».
Идея определённого присваивания заключается в том, что присваивание локальной переменной или пустому 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 присвоено независимо от того, является ли 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, если она определённо неприсвоена перед оператором while. Однако такое правило недостаточно для наших целей. Если e вычисляется как true, оператор S будет выполнен. Позже, если V присваивается оператором S, то в следующих итерациях V уже будет присвоена при вычислении e. В соответствии с предложенным правилом, V можно присваивать несколько раз, что как раз и является тем, чего мы пытались избежать, введя эти правила.
Пересмотренное правило было бы: "V определённо неприсвоено перед e, если она определённо неприсвоена перед оператором while и определённо неприсвоена после S". Однако при формулировании правила для S мы получаем: "V определённо неприсвоена перед S, если она определённо неприсвоена после 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 switch expression when true iff for every
yieldstatement 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.
Предположим, что 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 понятие определённого неприсвоения применяется только к переменным без начального значения. Если V - локальная переменная без начального значения, то только метод, к которому относится её объявление, может производить присваивания V. Если V - поле без начального значения, то только конструктор или инициализатор класса, содержащий объявление для 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 не инициализирована (и, кроме того, не обязательно инициализирована) перед блоком, который является телом конструктора, метода, инициализатора экземпляра или статического инициализатора, который объявляет V.
-
Пусть 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):
-
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 или оператора
throwправила switch. -
Если в блоке switch есть группа операторов switch с меткой, то V имеет [присвоенное] / [не присвоенное] значение после последнего оператора блока последней группы операторов switch с меткой.
-
Если в блоке switch нет метки
default, или если блок switch заканчивается меткой switch, за которой следует разделитель}, то V имеет [присвоенное] / [не присвоенное] значение после выражения селектора.
-
-
V имеет [присвоенное] / [не присвоенное] значение перед выражением селектора оператора
switchтогда и только тогда, когда V имеет [присвоенное] / [не присвоенное] значение перед операторомswitch. -
V имеет [присвоенное] / [не присвоенное] значение перед выражением правила 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 ((e) Ssynchronized (§14.19) тогда и только тогда, когда V получает [не]присвоенное значение после S.e) S -
V получает [не]присвоенное значение до
eтогда и только тогда, когда V получает [не]присвоенное значение до оператораsynchronized (.e) S -
V получает [не]присвоенное значение до S тогда и только тогда, когда V получает [не]присвоенное значение после
e.
Приведенные здесь правила охватывают операторы try-catch и try-catch-finally (finally§14.20.1, finally§14.20.2). Поскольку оператор try-with-resources (try§14.20.3) определяется посредством перевода в оператор try-catch-finally, то специальных правил для него предоставлять не нужно.
Эти правила применяются к каждому оператору try (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 метода или конструктора (
catch§8.4.1,catch§8.8.1) определенно присвоен (и более того, определенно не не присвоен) до тела метода или конструктора. -
Параметр исключения V предложения
catch(catch§14.20) определенно присвоен (и более того, определенно не не присвоен) до тела предложенияcatch.
-
V получает [не]присвоенное значение после пустого инициализатора массива (
e§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.