Compound assignment на char — рабочий код до символа за границей диапазона

Выглядит невинно: инкремент символа в цикле для генерации диапазона букв. Компилируется, работает на тесте с латиницей — и ломается там, где не ждёшь.

char c = 'z'; c += 1; System.out.println(c);

Здесь ничего не падает — просто печатает {, следующий символ после z в таблице Unicode. Проблема не в этом случае, а в том, что c += 1 — это скрытый каст. Compound assignment оператор в Java всегда включает неявное сужающее преобразование обратно к типу переменной слева.

Развёрнуто это выглядит так: c = (char) (c + 1). Явный каст компилятор вставляет сам, поэтому char c = 'a'; c++; компилируется без единого предупреждения, хотя char d = 'a'; d = d + 1; без каста — ошибка компиляции.

Ловушка возникает, когда диапазон символов формируют программно и не проверяют границу char — от 0 до 65535. Целочисленное переполнение здесь молчаливое: char не кинет исключение, просто перескочит через ноль по модулю 65536.

Что спросят следом: «почему тогда byte b = 10; b += 5; компилируется, а byte b = 10; b = b + 5; — нет?» Ответ: у compound assignment operator есть implicit narrowing cast, встроенный в спецификацию оператора — компилятор сам вставляет (byte) при +=. У обычного присваивания такого каста нет, b + 5 промоутится до int, и int нельзя присвоить byte без явного приведения.

Compound assignment — не сокращение записи, а оператор с собственным поведением приведения типов, которое вы не видите в коде.

Тренажёр: 600 вопросов, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки