АБОБА. Справочник по программированию на Java Методическое пособие
Скачать 242.41 Kb.
|
Сдвиг вправо без учета знакаКак было показано, при каждом выполнении операция >> автоматически заполняет старший бит его предыдущим содержимым. В результате знак значения сохраняется. Однако иногда это нежелательно. Например, при выполнении сдвига вправо в какомлибо значении, которое не является числовым, использование дополнительных знаковых разрядов может быть нежелательным. Эта ситуация часто встречается при работе со значениями пикселей и графическими изображениями. Как правило, в этих случаях требуется сдвиг нуля в позицию старшего бита независимо от его первоначального значения. Такое действие называют сдвигом вправо без учета знака. Для его выполнения используют операцию сдвига вправо без учета знака Java, >>>, которая всегда вставляет ноль в позицию старшего бита. Следующий фрагмент кода демонстрирует применение операции >>>. В этом примере значение переменной a установлено равным –1, все 32 бита двоичного представления которого равны 1. Затем в этом значении выполняется сдвиг вправо на 24 бита с заполнением старших 24 битов нулями и игнорированием обычно используемых дополнительных знаковых разрядов. В результате значение a становится равным 255. int a = -1; a = a >>> 24; Чтобы происходящее было понятнее, запишем эту же операцию в двоичной форме: 11111111 11111111 11111111 11111111 –1 в двоичном представлении типа int >>>24 00000000 00000000 00000000 11111111 255 в двоичном представлении типа int Часто операция >>> не столь полезна, как хотелось бы, поскольку она имеет смысл только для 32- и 64-разрядных значений. Помните, что в выражениях тип меньших значений автоматически повышается до int. Это означает применение дополнительных знаковых разрядов и выполнение сдвига по отношению к 32-разрядным, а не 8- или 16-разрядным значениям. То есть программист может подразумевать выполнение сдвига вправо без учета знака применительно к значению типа byte и заполнение нулями, начиная с бита 7. Однако в действительности это не так, поскольку фактически сдвиг будет выполняться в 32-разрядном значении. Этот эффект демонстрирует следующая программа. // Сдвиг без учета знака значения типа byte. class ByteUShift { static public void main(String args[]) { char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; byte b = (byte) 0xf1; byte c = (byte) (b >> 4); byte d = (byte) (b >>> 4); byte e = (byte) ((b & 0xff) >> 4); System.out.println(" b = 0x" + hex[(b >> 4) & 0x0f] + hex[b & 0x0f]); System.out.println(" b >> 4 = 0x" + hex[(c >> 4) & 0x0f] + hex[c & 0x0f]); System.out.println(" b >>> 4 = 0x" + hex[(d >> 4) & 0x0f] + hex[d & 0x0f]); System.out.println("(b & 0xff) >> 4 = 0x" + hex[(e >> 4) & 0x0f] + hex[e & 0x0f]); } } Из следующего вывода этой программы видно, что операция >>> не выполняет никаких действий по отношению к значениям типа byte. Для этого примера в качестве значения переменной b было выбрано произвольное отрицательное значение типа byte. Затем переменной c присваивается значение переменной b типа byte, сдвинутое вправо на четыре позиции, которое в связи с применением дополнительных знаковых разрядов равно 0xff. Затем переменной d присваивается значение переменной b типа byte, сдвинутое вправо на четыре позиции без учета знака, которым должно было бы быть значение 0x0f, но в действительности, из-за применения дополнительных знаковых разрядов во время повышения типа b до int перед выполнением сдвига, равное 0xff. Последнее выражение устанавливает значение переменной e равным значению типа byte переменной b, замаскированному до 8 бит с помощью операции AND и затем сдвинутому вправо на четыре позиции, что дает ожидаемое значение, равное 0x0f. Обратите внимание, что операция сдвига вправо без учета знака не применялась к переменной d, поскольку состояние знакового бита после выполнения операции AND было известно. b = 0xf1 b >> 4 = 0xff b >>> 4 = 0xff (b & 0xff) >> 4 = 0x0f Побитовые составные операции с присваиваниемПодобно алгебраическим операциям, все двоичные побитовые операции имеют составную форму, которая объединяет побитовую операцию с операцией присваивания. Например, следующие два оператора, выполняющие сдвиг вправо на четыре позиции в значении переменной a, эквивалентны: a = a >> 4; a >>= 4; Аналогично, эквивалентны и следующие два оператора, которые присваивают переменной a результат выполнения побитовой операции a OR b: a = a | b; a |= b; Следующая программа создает несколько целочисленных переменных, а затем использует составные побитовые операции с присваиванием для манипулирования этими переменными: class OpBitEquals { public static void main(String args[]) { int a = 1; int b = 2; int c = 3; a |= 4; b >>= 1; c <<= 1; a ^= c; System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("c = " + c); } } Эта программа создает следующий вывод: a = 3 b = 1 c = 6 |