К.Сьерра и Б.Бейтс в своей книге "Руководство по изучению SCJP" пишут
"Следующее допустимо byte b = 27;
, но только потому, что компилятор автоматически сужает буквальное значение до байта. Другими словами, компилятор вставляет приведение. Предыдущий код идентичен следующему: byte b = (byte) 27;
"
На мой взгляд, это объяснение неверно. Эти две строки кода идентичны?
По факту
byte b = 27;
просто константа. И сужение констант во время компиляции — единственная причина, по которой этот код действителен. Так что бросок не нужен. При сужении компилятор просто проверяет, подходит ли указанное значение к типу переменной. В спецификации говорится:
Сужающее примитивное преобразование может использоваться, если переменная имеет тип byte, short или char, а значение константного выражения равно представим в типе переменной.
Во втором случае
byte b = (byte) 27;
кастинг происходит во время выполнения, и значение примитива вычисляется в соответствии с определенными правилами. Компилятор не заботится о совместимости примитивных типов. Например
byte b = 5.0; // compile error
byte b = 277777777; // compile error
byte b = (byte) 5.0; // valid!
byte b = (byte) 277777777; // valid!!
Это заставляет меня думать, что преобразование расширения/сужения и приведение типов принципиально разные. Но в различных источниках они часто используются взаимозаменяемо. Это правильно? Происходит ли приведение под одеялом в случае неявного сужающего преобразования?
Кто-нибудь может объяснить реальное поведение компилятора в ситуации, описанной в приведенной выше книге?