Вид похож на этот , но не совсем. Я попытался просмотреть спецификацию языка и несколько других ресурсов, но не было никакого точного ответа о том, как типы операндов выбираются компилятором.
Но при сборке всей информации кажется, что:
byte x = (a>b) ? 10 : 20;
выдает ошибку, потому что существует неявное преобразование типа int
в byte
.
В более новых java версий, показанных компилятором:
error: incompatible types: possible lossy conversion from int to byte
Это потому, что второй и третий операнд в (a>b) ? 10 : 20
рассматривается как int
. Константы basei c цифра c всегда оцениваются как int
, и их необходимо явно уменьшить до byte
. Приведение возвращаемых (второго или третьего) операндов или целого оператора к байту предотвращает ошибку, поскольку он явно показывает компилятору, что потеря данных при преобразовании от int
к byte
не должна приниматься во внимание.
Приведение второго или третьего операнда к byte
прямо говорит, что каждое возвращение от этого троичного оператора должно рассматриваться как byte
.
Запись чего-то вроде:
int aa = 100000000;
byte zz = aa;
//or
double dd = 10.11d;
long xyx = dd;
приведет к тому же виду ошибки.
Причина всего этого в том, что продвижение меньшего примитива к верхнему не влияет на детерминированный c результат программы, но снижает (т. е. int на short) или отбрасывание плавающей запятой может привести к различным результатам.
Обратите внимание, что такие объявления не приводят к ошибке:
byte ooo = 100; //it throws an error if the value of ooo is higher than 127
//cause the `127` is the max value for byte type
int iii = ooo;
Строка, подобная:
byte x = (20>10) ? 10 : 20;
не выдает никаких ошибок времени выполнения / ошибки компилятора, потому что при наличии явных значений, предоставленных компилятору условия, можно просто оценить условие, которое приводит к: byte x = 10
. Мертвый код, то есть недостижимый оператор в Java, может быть получен с:
try {
throw new Exception();
} catch (Exception e) {
throw new Exception(e);
System.out.println(); //compiler shows this line as unreachable
}
Таким образом, для краткого заключения числовые литералы / константы оцениваются как тип int
, если они не являются явными присваивается указанному типу c. byte x = 10;
работает, потому что он явно говорит о назначении 10
байтовому типу, а 10
относится к типу byte
и не приводит к потере данных (назначение -129
или 10.1
throws ошибка).
С byte x = (a>b) ? 10 : 20;
дело в том, что все троичное выражение не вычисляется на лету, компилятор не знает, не изменились ли значения a
и b
где-то еще , Указание явных чисел или просто true/false
в условии троичного оператора делает результат выражения очевидным для компилятора (и для глаз разработчика).
После более тщательного изучения spe c из условного оператора он говорит:
Условный оператор? : использует логическое значение одного выражения, чтобы решить, какое из двух других выражений должно быть оценено.
С учетом сказанного, выбранный оператор результата оценивается ONLY , когда оператор условия оцененный (1-й результат, если истина, 2-й, если ложь).
Явное условие, такое как 20>10
или true
, оценивается во время компиляции, поэтому точное, явное значение присваивается в случае byte x = ...
.
Почему что-то такое маленькое, как:
int a = 10, b = 20;
byte x = (a>b) ? 10 : 20;
не оценивается во время компиляции и выдает ошибку?
Поскольку уже указанные числовые литералы оцениваются как int
и в вышеприведенном присваивании переменной x
переменная не является явной (напоминание, что выбранный оператор результата вычисляется после оценки условия).
Компилятор не является чем-то вроде полного анализатора кода c, пытающегося запросить это может привести к чрезмерно усложненному байт-коду.
Представьте себе более сложный пример, в котором значения a
и b
инициализируются в коде, но есть несколько операторов if
, которые могут изменить значения, присвоенные a
или b
. Затем компилятор должен сначала проверить, можно ли выполнить какой-либо из операторов if во время компиляции, чтобы определить, существует ли значение времени компиляции для одной из этих переменных, а затем создать условия для ternary/conditional operator
на основе этого, если одно из этих значений изменилось. И в результате мы получим много очень сложного кода, что обойдется без такого анализа.
Это очень простой пример, поэтому для разработчика он может выглядеть как wtf
, но для предотвращения компиляции такой случай будет слишком трудоемким, поскольку компилятор не может определить, прост ли предоставленный код или нет и не может оценить значения переменных для условий во время компиляции.