Можем ли мы сделать беззнаковый байт в Java


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

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

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

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

14 148

14 ответов:

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

Я просто попробовал это, и для байта -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) вы должны использовать другой тип integer, как short,int или long.

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

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

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"
}

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

int anUnsignedByte = (int) aSignedByte & 0xff;

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

как говорится, ничто не мешает вам просматривать a 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));

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

int unsignedInt = Byte.toUnsignedInt(myByte);

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

byte b = 255;
System.out.println((b < 0 ? 256 + b : b));

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

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

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

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

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

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

Почему вы не можете использовать любой другой тип данных?

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

хотя это может показаться раздражающим (исходя из C), что Java не включал беззнаковый байт в язык, это действительно не имеет большого значения, так как простая операция "b & 0xFF" дает беззнаковое значение для (подписанного) байта b в (редких) ситуациях, которые на самом деле необходимы. Биты на самом деле не меняются-только интерпретация (что важно только при выполнении, например, некоторых математических операций над значениями).

Если вы думаете, что ищете что-то вроде этого.

public static char toUnsigned(byte b) {
    return (char) (b >= 0 ? b : 256 + b);
}

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

int myInt = 144;

byte myByte = (byte) myInt;

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

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

выход:

myChar : 90

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

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

Если вы хотите беззнаковые байты в Java, просто вычесть 256 из числа, которое вас интересует. Он будет производить дополнение с отрицательным значением, которое является желаемым числом в байтах без знака.

пример:

int speed = 255; //Integer with the desired byte value
byte speed_unsigned = (byte)(speed-256);
//This will be represented in two's complement so its binary value will be 1111 1111
//which is the unsigned byte we desire.

вы должны использовать такие грязные хаки при использовании leJOS в программе блок NXT.

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

дело в том, что java подписала interger -128 до 127.. Можно представить без знака в java с:

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

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

Если вы попытаетесь добавить 244 байта в java, вы получите outOfIndexException.

Ура..