Побитовые операторы в Java только для целых и длинных?

Я написал следующий код в Eclipse:

byte b = 10;
/* some other operations */
b = ~b;

Затмение хотело приведение к байту в строке побитового дополнения. Он сказал: "Несоответствие типов: невозможно преобразовать из int в байт". Я также попробовал это с другими побитовыми операциями и на других целочисленных типах. Это было с коротким и голым же. Только длинные и целые могут использовать побитовые операции.

Для этого есть причина?

2 ответа

Решение

Одинарный (такой как ~) и бинарные операторы в Java подвергают свои операнды "унарному числовому продвижению" (JLS, раздел 5.6.1) и "бинарному числовому продвижению" (JLS, раздел 5.6.2), соответственно, причудливым терминам "продвигать вещи по крайней мере" int первый".

В частности, для унарного числового продвижения, цитируя раздел JLS, связанный выше:

Некоторые операторы применяют унарное числовое продвижение к одному операнду, который должен выдавать значение числового типа:

а также

... если операнд имеет тип byte, short или char типа времени компиляции, он повышается до значения типа int путем расширяющегося примитивного преобразования (§5.1.2).

(Двоичное числовое продвижение аналогично, работает с обоими операндами.)

Так что, даже если b это byte, ~b является int, так как b ценность была повышена до int первый.

Решение: вернуть его обратно в byte:

b = (byte) (~b);

Почему, Java?

Это оставляет вопрос, почему? Кажется, для операторов, которые я могу найти, инструкции байт-кода JVM для работы на byte s, short с и char с просто не существует. Например, используемый вами унарный оператор дополнения (~) реализован как операция "XOR" с -1 (все биты установлены). По этой ссылке:

tempSpock &= ~mask;

становится

25 iload_2 // Push local variable 2 (mask).
26 iconst_m1 // Push -1.
27 ixor // Bitwise EXCLUSIVE-OR top two ints: ~mask

Тем не менее, я могу найти только инструкции для XOR (и для других унарных и бинарных операторов тоже) для int с и long с (float а также double версия существует для других операторов, где это необходимо).

Итак, Java должна выполнить эти рекламные акции, потому что нет никаких инструкций байт-кода для выполнения этих операций над byte s, short с или char s.

Почему нет, JVM?

Это поднимает другой вопрос: почему JVM не поддерживает такие инструкции байт-кода? Кажется, ответ таков: "Потому что их было бы слишком много, чтобы закодировать их все в однобайтовом наборе инструкций". Согласно спецификации JVM, раздел 2.11.1,

Учитывая размер однобайтового кода операции виртуальной машины Java, типы кодирования в коды операций оказывают давление на разработку набора инструкций. Если бы каждая типизированная инструкция поддерживала все типы данных времени исполнения виртуальной машины Java, было бы больше инструкций, чем можно было бы представить в байте. Вместо этого набор команд виртуальной машины Java обеспечивает пониженный уровень поддержки типов для определенных операций. Другими словами, набор инструкций намеренно не ортогональн. Отдельные инструкции могут использоваться для преобразования между неподдерживаемыми и поддерживаемыми типами данных по мере необходимости.

(акцент мой)

В заключение, набор однобайтовых команд JVM исключает инструкции байт-кода для большинства операций над byte s, char с и short s, требующие одинарного числового продвижения и двоичного числового продвижения.

Да, типы меньше чем int пройти продвижение при использовании в качестве операндов для большинства операторов. Они эффективно брошены на int первый. Поэтому в приведенном выше коде тип результата int, Смотрите этот раздел JLS для полной информации.

Что касается того, почему Java делает это, я не уверен. Но одна правдоподобная причина в том, что C делает это, и поддержание знакомой семантики, вероятно, было целью разработки языка.

Другие вопросы по тегам