Можем ли мы сделать неподписанный байт в Java - PullRequest
170 голосов
/ 24 ноября 2010

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

Я попытался преобразовать их с помощью следующего решения, полученного из стека.Переполнение.

public static int unsignedToBytes(byte a)
{
    int b = a & 0xFF;
    return b;
}

Но когда он снова преобразуется в байты, я получаю те же подписанные данные.Я пытаюсь использовать эти данные в качестве параметра для функции Java, которая принимает в качестве параметра только байт, поэтому я не могу использовать любой другой тип данных.Как я могу решить эту проблему?

Ответы [ 15 ]

181 голосов
/ 24 ноября 2010

Тот факт, что примитивы подписаны в Java, не имеет отношения к тому, как они представлены в памяти / транзите - байт составляет всего 8 бит, и независимо от того, интерпретируете ли вы его как диапазон со знаком или нет, зависит от вас.Нет волшебного флага, чтобы сказать «это подписано» или «это не подписано».

Поскольку примитивы подписаны, компилятор Java не позволит вам присвоить байту значение больше +127 (или меньше, чем-128).Тем не менее, ничто не помешает вам понизить int (или short) для достижения этой цели:

int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)

/*
 * Will print a negative int -56 because upcasting byte to int does
 * so called "sign extension" which yields those bits:
 * 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
 *
 * But you could still choose to interpret this as +200.
 */
System.out.println(b); // "-56"

/*
 * Will print a positive int 200 because bitwise AND with 0xFF will
 * zero all the 24 most significant bits that:
 * a) were added during upcasting to int which took place silently
 *    just before evaluating the bitwise AND operator.
 *    So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
 * b) were set to 1s because of "sign extension" during the upcasting
 *
 * 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
 * &
 * 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
 * =======================================
 * 0000 0000 0000 0000 0000 0000 1100 1000 (200)
 */
System.out.println(b & 0xFF); // "200"

/*
 * You would typically do this *within* the method that expected an 
 * unsigned byte and the advantage is you apply `0xFF` only once
 * and than you use the `unsignedByte` variable in all your bitwise
 * operations.
 *
 * You could use any integer type longer than `byte` for the `unsignedByte` variable,
 * i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
 * it would get casted to `int` anyway.
 */
void printUnsignedByte(byte b) {
    int unsignedByte = b & 0xFF;
    System.out.println(unsignedByte); // "200"
}
100 голосов
/ 24 ноября 2010

Я не уверен, что понимаю ваш вопрос.

Я только что попробовал это, и для байта -12 (значение со знаком) он вернул целое число 244 (эквивалентно значению байта без знака, но напечатано как int):

  public static int unsignedToBytes(byte b) {
    return b & 0xFF;
  }

  public static void main(String[] args) {
    System.out.println(unsignedToBytes((byte) -12));
  }

Это то, что вы хотите сделать?

Java не позволяет выражать 244 как значение byte, как и C. Чтобы выразить натуральные числа выше Byte.MAX_VALUE (127), вы должны использовать другой целочисленный тип, такой как short, int или long.

39 голосов
/ 24 ноября 2010

Язык Java не предоставляет ничего похожего на ключевое слово unsigned.byte в соответствии со спецификацией языка представляет значение в диапазоне от -128 до 127. Например, если byte приведен к int Java будет интерпретировать первый бит как знак и использовать расширение знака .

При этом ничто не мешает вам рассматривать byte просто как 8 бит и интерпретировать эти биты как значение между 0 и 255. Просто имейте в виду, что вы ничего не можете сделать, чтобы заставитьВаша интерпретация на чужой метод.Если метод принимает byte, то этот метод принимает значение в диапазоне от -128 до 127, если явно не указано иное.

Вот пара полезных преобразований / манипуляций для вашего удобства:

Преобразование в / из int

// From int to unsigned byte
int i = 200;                    // some value between 0 and 255
byte b = (byte) i;              // 8 bits representing that value

// From unsigned byte to int
byte b = 123;                   // 8 bits representing a value between 0 and 255
int i = b & 0xFF;               // an int representing the same value

(или, если вы используете Java 8+, используйте Byte.toUnsignedInt.)

Парсинг / форматирование

Лучше всего использовать приведенные выше преобразования:

// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");

// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));

Арифметика

Представление из 2-х дополнений "просто работает"сложение, вычитание и умножение:

// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;

byte sum  = (byte) (b1 + b2);  // 215
byte diff = (byte) (b1 - b2);  // 185
byte prod = (byte) (b2 * b2);  // 225

Деление требует ручного преобразования операндов:

byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));
34 голосов
/ 24 ноября 2010

В Java нет примитивных байтов без знака. Обычное дело - привести его к большему типу:

int anUnsignedByte = (int) aSignedByte & 0xff;
20 голосов
/ 02 сентября 2015

Я думаю, что другие ответы касались представления памяти, и то, как вы их обрабатываете, зависит от контекста того, как вы планируете его использовать.Я добавлю, что В Java 8 добавлена ​​поддержка работы с неподписанными типами .В этом случае вы можете использовать Byte.toUnsignedInt

int unsignedInt = Byte.toUnsignedInt(myByte);
4 голосов
/ 16 ноября 2012

Примечание: если вы хотите распечатать его, вы можете просто сказать

byte b = 255;
System.out.println((b < 0 ? 256 + b : b));
1 голос
/ 04 апреля 2014

Адамски предоставил лучший ответ, но он не совсем полный, поэтому прочитайте его ответ, поскольку он объясняет детали, которыми я не являюсь.

Если у вас есть системная функция, для которой требуется неподписанный байтпереданный ему, вы можете передать подписанный байт, так как он будет автоматически обрабатывать его как неподписанный байт.

Таким образом, если системной функции требуется четыре байта, например, 192 168 0 1 как неподписанные байты, вы можете передать -64 -88 0 1, и функция все еще будет работать, потому что передача их функции отключит их подпись.

Однако вряд ли у вас возникнет эта проблема, поскольку системные функции скрыты за классами длякросс-платформенная совместимость, хотя некоторые методы чтения java.io возвращают невыгруженные байты как целые числа.

Если вы хотите, чтобы это работало, попробуйте записать подписанные байты в файл и прочитать их обратно как неподписанные байты.

0 голосов
/ 09 марта 2019

Вы также можете:

public static int unsignedToBytes(byte a)
{
    return (int) ( ( a << 24) >>> 24);
}    

Объяснение:

Допустим, a = (byte) 133;

В памяти оно хранится как: "1000 0101"(0x85 в шестнадцатеричном виде)

Таким образом, его представление переводит без знака = 133, со знаком = - 123 (как дополнение 2)

a << 24 </strong>

Когда сдвиг влево выполняется на 24 бита влево, результат теперь представляет собой 4-байтовое целое число, которое представляется в виде:

"10000101 00000000 00000000 00000000" (или "0x85000000" в шестнадцатеричном формате)

, тогда мы имеем

(a << 24) <strong>>>> 24

и он снова сдвигается на правильные 24 бита, но заполняется начальными нулями.Таким образом, это приводит к:

"00000000 00000000 00000000 10000101" (или "0x00000085" в шестнадцатеричном формате)

и это беззнаковое представление, равное 133.

Если выпопытался привести a = (int) a;, что произойдет, если он сохранит представление байта для дополнения 2 и сохранит его как int, а также дополнение до 2:

(int) "10000101" ---> "11111111 11111111 11111111 10000101"

И это переводится как: -123

0 голосов
/ 26 января 2016

Да и нет. Я копался с этой проблемой. Как я понимаю это:

Дело в том, что Java подписал интергер от -128 до 127 .. Можно представить неподписанный в Java с:

public static int toUnsignedInt(byte x) {
    return ((int) x) & 0xff;
}

Если вы, например, добавляете число без знака -12, чтобы получить без знака, вы получаете 244. Но вы можете снова использовать этот номер в знаке, его нужно перевести обратно в число со знаком, и оно снова будет -12.

Если вы попытаетесь добавить 244 к байту Java, вы получите исключениеOfIndexException.

Приветствие ..

0 голосов
/ 10 апреля 2015

В Java нет неподписанного байта, но если вы хотите отобразить байт, вы можете сделать,

int myInt = 144;

byte myByte = (byte) myInt;

char myChar = (char) (myByte & 0xFF);

System.out.println("myChar :" + Integer.toHexString(myChar));

Выход:

myChar : 90

Для получения дополнительной информации, пожалуйста, проверьте, Как отобразить шестнадцатеричное / байтовое значение в Java .

...