Неподписанные байты в Java - PullRequest
       4

Неподписанные байты в Java

15 голосов
/ 02 сентября 2011

Байты в Java подписаны по умолчанию. В других сообщениях я вижу, что обходной путь для байтов без знака выглядит примерно так: int num = (int) bite & 0xFF

Может кто-нибудь объяснить мне, почему это работает и преобразует подписанный байт в неподписанный байт, а затем в его соответствующее целое число? ANDing байт с 11111111 приводит к тому же байту - верно?

Ответы [ 5 ]

25 голосов
/ 02 сентября 2011

Тип преобразования имеет более высокий приоритет, чем оператор &. Поэтому вы сначала приводите к int, затем к AND для того, чтобы замаскировать все установленные старшие биты, включая «знаковый бит» нотации дополнения двух, которую использует java, оставляя вам только положительное значение оригинальный байт. E.g.:

let byte x = 11111111 = -1
then (int) x = 11111111 11111111 11111111 11111111
and x & 0xFF = 00000000 00000000 00000000 11111111 = 255

и вы фактически удалили знак из исходного байта.

15 голосов
/ 02 сентября 2011

AND Байт с 11111111 приводит к одному и тому же байту - верно?

Кроме того, что вы ANDD с 00000000000000000000000011111111, потому что 0xFF является буквальным int - нет byte литералы в Java.Таким образом, происходит то, что byte повышается до int (типовая передача не нужна), его знак расширяется (т. Е. Сохраняется возможно отрицательное значение byte, но затем расширение знака возвращается, используя AND с помощьювсе эти нули. Результатом является int, который имеет в качестве своих младших значащих битов точно прежний byte и, таким образом, значение, которое имел бы byte, было бы без знака.

9 голосов
/ 26 мая 2015

В Java 8 такой метод появился в байтовом классе:

/**
 * Converts the argument to an {@code int} by an unsigned
 * conversion.  In an unsigned conversion to an {@code int}, the
 * high-order 24 bits of the {@code int} are zero and the
 * low-order 8 bits are equal to the bits of the {@code byte} argument.
 *
 * Consequently, zero and positive {@code byte} values are mapped
 * to a numerically equal {@code int} value and negative {@code
 * byte} values are mapped to an {@code int} value equal to the
 * input plus 2<sup>8</sup>.
 *
 * @param  x the value to convert to an unsigned {@code int}
 * @return the argument converted to {@code int} by an unsigned
 *         conversion
 * @since 1.8
 */
public static int toUnsignedInt(byte x) {
    return ((int) x) & 0xff;
}
2 голосов
/ 02 сентября 2011

Как вы видите, результат int не байт

Как это работает, скажем, у нас есть byte b = -128;, это представляется как 1000 0000, так что происходит, когда вы выполняете свою строку?Давайте для этого воспользуемся временным int, скажем:
int i1 = (int)b; i1 теперь равен -128, и это фактически представлено в двоичном виде следующим образом:

1111 1111 1111 1111 1111 1111 1000 0000

Так как же i1 & 0xFF выглядит в двоичном виде?

1111 1111 1111 1111 1111 1111 1000 0000
&
0000 0000 0000 0000 0000 0000 1111 1111

, что приводит к

0000 0000 0000 0000 0000 0000 1000 0000

, и это ровно 128, что означает, что ваше значение со знаком преобразовано в беззнаковое.

Редактировать
Преобразовать байт -128 .. 127 в 0 .. 255

int unsignedByte = 128 + yourByte;

Вы не можете представлять значения от 128 до 255 с помощью байта, вы должны использовать что-то еще, например, int или smallint.

0 голосов
/ 02 сентября 2011

Да, но таким образом вы можете быть уверены, что никогда не получите номер> 255 или <0. </p>

Если первый бит равен 1, число является отрицательным. Если вы конвертируете байт в int, если он отрицательный, он будет предварительно добавлен с 1 байтом, а если положительный, с 0 байтами. Запуск подпрограммы and удалит все байты, оставшиеся от первых 8. Это фактически добавляет 256 к отрицательным байтам.

...