Маскировка байтов в java

Есть кое-что, что я изо всех сил пытаюсь понять, у меня есть этот фрагмент кода:

public class HelloWorld{

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

public static short readShort(byte[] b) {
    return (short)(readByte(b[0]) | readByte(b[1]) << 8);
}

 public static void main(String []args){
    byte[] b = {(byte)0x94, 0x00};
    System.out.println(readShort(b));

 }
}

Теперь возвращаемый результат равен 148, но я не понимаю, почему, если я удалю маскировку "& 0xFF", результат изменится, если вы читаете по 1 байту за раз, маскировка 0xFF не должна влиять на byte (по крайней мере, это то, что я знаю), мой друг пытался объяснить мне это, и он сказал, что это связано с тем, что байт "0x94" не имеет знака, и приведение происходит в методе readByte, но я не мог этого понять, и я Мне действительно трудно понять, почему вам нужна маскировка, чтобы правильно прочитать байт, заранее спасибо всем, кто попытается мне помочь!


person user3497284    schedule 18.04.2014    source источник
comment
Ознакомьтесь с моим сообщением об этом doridori.github.io/Java-Bitshifting-Bytes.   -  person Dori    schedule 29.04.2015


Ответы (1)


Байт — это подписанные данные. Итак, 0x94 - это -108. Когда вы возвращаете его как int, вы возвращаете -108, расширенное до 4 байтов, что НЕ является 0x94 (это FFFFFF94). Это, очевидно, испортит ваше более позднее ИЛИ. Маска исправляет это, потому что байт 0x94 преобразуется в целое число перед И с ним с 0xFF, поэтому И отбрасывает эти лишние 1 из отрицательного расширения.

person Gabe Sechan    schedule 18.04.2014
comment
Я знаю, что, поскольку вы возвращаете его как int, вы добавляете еще 3 байта к исходному, но я все еще чего-то не понимаю, и я не уверен, что, я попытаюсь объяснить это, как я ВИЖУ ЭТО шаг за шагом, и, возможно, вы могли бы понять что я не понимаю, скажем, у вас есть этот байт 0x94 в двоичном формате, его 10010100, поэтому вы расширяете его еще на 3 байта, он становится 00000000 00000000 00000000 10010100, так что теперь вы получаете это в двоичном виде, теперь после маскировки вы получите 10010100, и когда вы вернете его, вы получим 148 в десятичном виде, теперь без маскировки вы вернете 00000000 00000000 00000000 10010100 в двоичном формате, который ВСЕ ЕЩЕ 148 в dec - person user3497284; 19.04.2014
comment
Он не расширяется со всеми 0 байтами. Он знак расширяется. Отрицательные числа расширяются со всеми единицами, а положительные числа расширяются со всеми нулями. Поскольку 0x94 как байт на самом деле отрицательный, он расширяется до FFFFFF94, а не 00000094. Это то, что вам не хватает. - person Gabe Sechan; 19.04.2014
comment
хорошо, поэтому я получаю 11111111 11111111 11111111 01101100 (последний байт = положительный 108), а второе целое число, которое мы получаем, равно 00000000 00000000 00000000 00000000, и когда мы их ИЛИ, мы получаем первое целое число, и после приведения к короткому мы получаем 11111111 01111111 01000000 он снова печатает -108? извините, мне трудно объяснить мне, что мне всегда трудно понять побитовую операцию и все, что с ней связано :| - person user3497284; 19.04.2014
comment
Таким образом, readByte без маски возвращает FFFFFF94 для индекса 0 и FFFFFF00 для индекса 1. ЗАТЕМ вы сдвигаете второй и выполняете их вместе, что равно FFFFFF94 | FFFF0000 = FFFFFF94. Затем вы переводите его в шорт, который усекает его (сохраняя знак) до FF94. FF94 это -108. Так вот почему это происходит. Правило, которое нужно убрать: в Java всегда нужно маскировать перед преобразованием типов. - person Gabe Sechan; 19.04.2014
comment
Хорошо, спасибо, но могу ли я узнать, как вы конвертируете шестнадцатеричное число в целое число со знаком, потому что все калькуляторы, которые я использую, сразу говорят, что 94 в шестнадцатеричном формате равно 148 в десятичном, так как же работает преобразование в десятичное со знаком? - person user3497284; 19.04.2014
comment
Посмотрите на MSB (старший значащий бит) в зависимости от размера переменной. Если это 1, число отрицательное. Если это 0, положительный. Это работает со всем, кроме поплавков или двойников. Вы также можете прочитать о том, как отрицательные числа работают в двоичном формате — это называется арифметикой с дополнением до двух — en .wikipedia.org/wiki/Two%27s_complement - person Gabe Sechan; 19.04.2014
comment
поэтому он инвертирует все биты и добавляет + 1, чтобы получить отрицательное / если вы разделяете его в десятичном виде, это похоже на получение беззнакового значения и вычитание из него максимально возможного значения, которое может содержать тип данных, скажем, короткий, затем вычтите 65536? - person user3497284; 19.04.2014
comment
Да, это эквивалентно, если число отрицательное. - person Gabe Sechan; 19.04.2014