Как заявляет trojanfoe, ваша путаница с результатами вашего кода частично связана с расширением знака. Я постараюсь добавить более подробное объяснение, которое может помочь в вашей путанице.
char a = '\uffff';
byte b = (byte)a; // b = 0xFF
Как вы заметили, это приводит к потере информации. Это считается сужающим преобразованием . Преобразование символа в байт «просто отбрасывает все, кроме n младших битов».
Результат: 0xFFFF -> 0xFF
char c = (char)b; // c = 0xFFFF
Преобразование байта в символ считается специальным преобразованием . Он фактически выполняет ДВЕ преобразования. Во-первых, байт является расширенным SIGN (новые биты старшего разряда копируются из старого битового знака) в int (нормальное расширяющее преобразование). Во-вторых, int преобразуется в символ с сужающимся преобразованием.
Результат: 0xFF -> 0xFFFFFFFF -> 0xFFFF
int d = (int)c; // d = 0x0000FFFF
Преобразование символа в int считается расширяющимся преобразованием . Когда тип char расширяется до целочисленного типа, он расширяется нулями (новые биты старшего разряда устанавливаются в 0).
Результат: 0xFFFF -> 0x0000FFFF
. При печати это даст вам 65535.
Три ссылки, которые я предоставил, являются официальными подробностями Спецификации языка Java о примитивных преобразованиях типов. Я настоятельно рекомендую вам взглянуть. Они не очень многословны (и в этом случае относительно просты). Он подробно описывает, что будет делать Java за кулисами при преобразовании типов Это общая область недопонимания для многих разработчиков. Оставьте комментарий, если вы все еще не понимаете какой-либо шаг.