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

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

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

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

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

14 ответов


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

Я только что попробовал это, и для byte -12 (signed value) он вернул целое число 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). Тем не менее, нет ничего, чтобы остановить вас downcasting 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"
}

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

int anUnsignedByte = (int) aSignedByte & 0xff;

язык 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));

Я думаю, что другие ответы охватывают представление памяти, и как вы их обрабатываете, зависит от контекста того, как вы планируете его использовать. Я добавлю, что в 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 возвращают unsighed байты как 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.. Можно представить unsigned в java с помощью:

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

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

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

Ура..