Условный оператор Java: тип результата
Я немного озадачен условным оператором. Рассмотрим следующие две строки:
Float f1 = false? 1.0f: null;
Float f2 = false? 1.0f: false? 1.0f: null;
Почему f1 становится null, а второй оператор выдает исключение NullPointerException?
Langspec-3.0 para 15.25 sais:
в противном случае второй и третий операнды имеют типы S1 и S2 соответственно. Пусть T1-тип, который является результатом применения преобразования бокса в S1, и пусть T2-тип, который является результатом применения бокса преобразование в С2. Тип условное выражение является результатом применения преобразования захвата (§5.1.10) - lub(T1, T2) (§15.12.2.7).
и false?1.0f:null
T1-Float, а T2-тип null. Но каков результат lub(T1,T2)
? Этот пункт 15.12.2.7 просто немного чересчур ...
кстати, я использую 1.6.0_18 в Windows.
PS: Я знаю, что Float f2 = false? (Float) 1.0f: false? (Float) 1.0f: null;
не бросает NPE.
5 ответов
разница заключается в статическом типировании выражений во время компиляции:
резюме
E1: `(false ? 1.0f : null)`
- arg 2 '1.0f' : type float,
- arg 3 'null' : type null
- therefore operator ?: : type Float (see explanation below)
- therefore autobox arg2
- therefore autobox arg3
E2: `(false ? 1.0f : (false ? 1.0f : null))`
- arg 2 '1.0f' : type float
- arg 3 '(false ? 1.0f : null)' : type Float (this expr is same as E1)
- therefore, outer operator ?: : type float (see explanation below)
- therefore un-autobox arg3
Подробное Описание:
вот мое понимание от чтения через спец и работает в обратном направлении от результата, который вы получили. Это сводится к типу третьего операнда f2 внутренний conditional является нулевым типом, а тип третьего операнда f2 внешний условный считается плавающим.
Примечание: важно помнить, что определение типа и вставка кода бокса/распаковки выполняется во время компиляции. Фактическое выполнение кода бокса/распаковки выполняется во время выполнения.
Float f1 = (false ? 1.0f : null);
Float f2 = (false ? 1.0f : (false ? 1.0f : null));
условное f1 и внутреннее условное F2:(ложные ? 1.0 f: null)
условное f1 и внутреннее условное f2 идентичны:(ложные ? 1.0 f : null). Типы операндов в условном f1 и внутреннем условном F2:
type of second operand = float
type of third operand = null type (§4.1)
большинство правил в §15.25 передаются, и эта окончательная оценка действительно применяется:
в противном случае второй и третий операнды имеют типы S1 и S2 соответственно. Пусть T1-тип, который является результатом применения преобразования бокса в S1, и T2-тип, который является результатом применения преобразования бокса в S2. Тип условное выражение является результатом применения преобразования захвата (§5.1.10) в lub(T1, T2) (§15.12.2.7).
S1 = float
S2 = null type
T1 = Float
T2 = null type
type of the f1 and f2 inner conditional expressions = Float
поскольку для f1 присвоение является плавающей ссылочной переменной, результат выражения (null) успешно назначен.
для внешнего условного F2:(ложные ? 1.0 f: [F2 внутреннее условное])
для внешнего условного F2 типы являются:
type of second operand = float
type of third operand = Float
обратите внимание на разницу в типах операндов по сравнению с внутренними условными обозначениями f1/f2, которые ссылаются на null буквальное напрямую (§4.1). Из-за этого различия, имеющего 2 числовых конвертируемых типа, это правило из §15.12.2.7 применяется:
в противном случае, если второй и третий операнды имеют типы, которые могут быть конвертированы (§5.1.8) к числовым типам, тогда там есть несколько случаев: ...
- в противном случае, двоичное числовое продвижение (§5.6.2) применяется к типам операндов, а тип условного выражения является повышенным типом второго и третьего операндов. Обратите внимание, что binary numeric promotion выполняет преобразования распаковывания (§5.1.8) и преобразование набора значений (§5.1.13).
из-за распаковки преобразование выполняется на результат F2 внутреннего условного (null), возникает исключение NullPointerException.
следующее вызовет NPE при попытке присвоить null примитиву
float f1 = false ? 1.0f: null;
Я считаю, что это то, что вызывает NPE во втором заявлении. Поскольку первая тройка возвращает float для true, она также пытается преобразовать false в float.
первый оператор не преобразуется в null, так как требуемым результатом является Float
Это, например, это не будет бросать NPE, поскольку его больше не нужно конвертировать в примитивный
Float f = false? new Float(1.0f): true ? null : 1.0f;
Я думаю, что переписывание кода делает объяснение более ясным:
float f = 1.0f;
Float null_Float = false? f : null; // float + null -> OK
Float null_Float2 = false? (Float)f : null_Float; // Float + Float -> OK
Float npe = false? f : null_Float; // float + Float -> NPE
таким образом, NPE-это когда мы пытаемся сделать что-то вроде:
Float npe = false? 1.0f : (Float)null;
похоже, что JVM пытается распаковать второй null в float вместо Float, таким образом, NullPointerException. Сам ударил один раз. Мое мнение, что второе если это потому что правда часть первая если оценивает как поплавок, а не поплавок.
подумав, я думаю, что это способ Java сказать вам, что вы делаете что-то странное. Просто не гнездитесь тройные ifs, и вы будете будь в порядке: -)