Oracle инженер Lois Foltan подтвердила то, во что многие уже перестали верить: JEP 401 (Value Classes and Objects) будет интегрирован в основной OpenJDK и нацелен на JDK 28. Изменение настолько масштабное, что остальных коммитеров попросили на время воздержаться от крупных коммитов — один только pull request добавляет 197 тысяч строк кода в 1816 файлах. Но это превью, отключённое по умолчанию. Брайан Гётц сразу остудил пыл: «это только первая часть Valhalla».
Проект стартовал в 2014 году с амбициозной целью — стереть разрыв между удобными классами и быстрыми примитивами. Слоган: «пишется как класс, работает как int». В Java всё, кроме восьми примитивов — ссылочный тип. Каждый объект лежит в куче с заголовком, каждый доступ к полю требует разыменования указателя. На масштабе это превращается в проблему: массив из миллиона Point — это миллион указателей на разбросанные по куче объекты с заголовками. Такая компоновка — «пушистая», как её называет Гётц. Мечта — плотная укладка, где данные лежат рядом, чтобы использовать кэш-линии процессора.
Escape analysis может оптимизировать, но он непредсказуем. Стоит объекту попасть в массив или поле — и всё, аллокация возвращается. Альтернатива — кодировать данные вручную: три байта r, g, b вместо класса Color. Быстро, но небезопасно и нечитаемо. Valhalla даёт третий путь.
За годы команда построила пять прототипов. Ранние шли в «Q World» — отдельные дескрипторы и байткоды для value-типов. Прорыв случился в «L World» (около 2019): value-типы начали использовать тот же L-дескриптор, что и ссылки. Неожиданно это сработало без серьёзных компромиссов. Выяснилось, что модель для JVM и модель для языка не обязаны совпадать на 100% — JVM может быть целью трансляции. Сейчас, в JEP 401, мы получаем value class (объявляется модификатором value). Его экземпляры — value objects без идентичности. Ключевое: value class — всё ещё ссылочный тип, может быть null. Ненулловые типы — отдельный, будущий JEP.
Отсутствие идентичности меняет многое. == теперь проверяет не адрес, а заменяемость (все поля рекурсивно). synchronized на таком объекте выбросит IdentityException. JVM получает два механизма оптимизации: скаляризацию (поля раскладываются по регистрам без аллокации) и уплотнение в куче (объект пишется прямо в поле или ячейку массива как битовый вектор). Даже Integer, Long и другие обёртки становятся value-классами — Integer[] начинает приближаться по эффективности к int[].
Но полная картина в JDK 28 не сложится. Специализированные дженерики (плоские ArrayList<Point>) и 128-битные кодировки — в будущих релизах. Следующий LTS, скорее всего, JDK 29 в сентябре 2027. Сейчас — время экспериментировать и отправлять обратную связь. Это один из глубочайших сдвигов в платформе: предположение «каждый объект имеет идентичность», верное с 1995 года, наконец перестаёт быть обязательным.