Выполнение этой программы дает следующий результат:Original message: This is a testEncoded message: 01+xl+x9x,=+,Decoded message: This is a test
Как видите, в результате двух операций поразрядного исключающего ИЛИ с одним и тем же ключом получается дешифрованное сообщение, совпадающее с исходным.
Унарная операция поразрядного НЕ (или дополнения до 1) изменяет на обратное состояние всех битов операнда. Так, если некоторая целочисленная переменная А содержит значение с двоичным представлением 10010110, то в результате поразрядной операции ~А получится двоичная комбинация 01101001.
Ниже приведен пример программы, демонстрирующий применение операции поразрядного НЕ. Эта программа отображает число и его дополнение в двоичном представлении.// Демонстрация операции поразрядного НЕ.class NotDemo { public static void main(String args[]) { byte b = -34; for(int t=128; t > 0; t = t/2) { if((b & t) != 0) System.out.print("1 "); else System.out.print("0 ") ; } System.out.println() ; // изменить на обратное состояние всех битов b = (byte) ~b; for(int t=128; t > 0; t = t/2) { if((b & t) != 0) System.out.print("1 ") ; else System.out.print("0 "); } }}
Выполнение этой программы дает следующий результат:1 1 0 1 1 1 1 00 0 1 0 0 0 0 1Операторы сдвига
В Java предусмотрена возможность сдвига битов, составляющих числовое значение, влево или вправо на заданное количество позиций. Для этой цели в Java предоставляются три перечисленных ниже оператора сдвига.<<Сдвиг влево>>Сдвиг вправо>>>Сдвиг влево без знака
Ниже приведена общая форма для этих операторов.значение << число_битовзначение >> число_битовзначение >>> число_битов
где число_битов — это число позиций двоичных разрядов, на которое сдвигается указанное значение.
При сдвиге влево освободившиеся младшие разряды заполняются нулями. А при сдвиге вправо дело обстоит немного сложнее. Как известно, признаком отрицательного целого числа является единица в старшем разряде, поэтому при сдвиге вправо старший (знаковый) разряд сохраняется. Если число положительное, то в него записывается нуль, а если отрицательное — единица.
Помимо сохранения знакового разряда, необходимо помнить еще об одной особенности сдвига вправо. Отрицательные числа в Java (как, впрочем, и в других языках программирования) представлены в виде дополнения до двух. Для того чтобы преобразовать положительное число в отрицательное, нужно изменить на обратное состояние всех битов его двоичного представления, а к полученному результату прибавить единицу. Так, значение -1 имеет байтовое представление 11111111. Сдвинув это значение вправо на любое число позиций, мы снова получим -1!
Если при сдвиге вправо не требуется сохранять знаковый разряд, то можно воспользоваться сдвигом вправо без знака (оператором »>). В этом случае освободившиеся старшие разряды всегда будут заполняться нулями. Именно поэтому такая операция называется еще сдвигом с заполнением нулями. Сдвигом вправо без знака удобно пользоваться для обработки нечисловых значений, в том числе кодов состояния.
При любом сдвиге теряются те биты, которые сдвигаются. Циклический сдвиг в Javaне поддерживается, и поэтому нет возможности восстановить потерянные разряды.
Ниже приведен пример программы, демонстрирующий эффект от применения операторов сдвига влево и вправо. В двоичном представлении исходного целочисленного значения 1 установлен лишь младший разряд. К этому значению восемь раз применяется операция сдвига влево. После каждого сдвига на экран выводится восемь младших разрядов числа. Затем единица устанавливается в восьмом двоичном разряде числа и производятся его сдвиги вправо.// Демонстрация операторов « и ».class ShiftDemo { public static void main(String args[]) { int val = 1; for(int i = 0; i < 8; i++) { for(int t=128; t > 0; t = t/2) { if((val & t) != 0) System.out.print("1 "); else System.out.print("0 "); } System.out.println() ; val = val « 1; // сдвинуть влево } System.out.println(); val = 128; for(int i = 0; i < 8; i++) { for(int t=128; t > 0; t = t/2) { if((val & t) != 0) System.out.print("1 "); else System.out.print("0 "); } System.out.println() ; val = val >> 1; // сдвинуть вправо } }}
Результат выполнения данной программы выглядит следующим образом:00000001000000100000010000001000000100000010000001000000100000001000000001000000001000000001000000001000000001000000001000000001
Выполняя сдвиг значений типа byte и short, необходимо соблюдать осторожность, поскольку исполняющая система Java автоматически преобразует их в тип int и лишь затем вычисляет выражение с оператором сдвига. Так, если сдвинуть вправо значение типа byte, оно будет сначала продвинуто к типу int, а результат сдвига будет также отнесен к типу int. Обычно такое преобразование не влечет за собой никаких последствий. Но если попытаться сдвинуть отрицательное значение типа byte или short, то при продвижении к типу int оно будет дополнено знаком, а следовательно, старшие его разряды будут заполнены единицами. Это вполне оправдано при обычном сдвиге вправо. Но при выполнении сдвига с заполнением нулями в байтовом представлении числа неожиданно появятся 24 единицы, которые придется дополнительно сдвинуть, прежде чем в нем появятся нули.Поразрядные составные операторы присваивания
составные операторы присваиванияВсе двоичные поразрядные операторы имеют укороченную форму и могут быть использованы в составных операциях присваивания. Например, в двух приведенных ниже операторах переменной х присваивается результат выполнения операции исключающее ИЛИ над первоначальным значением переменной х и числовым значением 127.х = х А 127;х А= 127;
Пример для опробования 5.3.Создание класса ShowBits
В данном проекте предстоит создать класс ShowBits, который позволит отображать любое целочисленное значение в двоичном виде. Этот класс может оказаться очень полезным при разработке некоторых программ. Так, если требуется отладить код драйвера устройства, возможность контролировать поток данных в двоичном виде окажется весьма кстати.
Последовательность действий
Создайте новый файл ShowBits Demo. j ava.
Создайте класс ShowBits, начав его со следующего кода: class ShowBits { int numbits; ShowBits(int n) { numbits = n; } }
Конструктор класса ShowBits позволяет создавать объекты, отображающие заданное число битов. Например, для создания объекта, отображающего 8 младших битов некоторого значения, служит следующее выражение: ShowBits byteval = new ShowBits(8)
Число битов, предназначаемых для отображения, сохраняется в переменной экземпляра numbits.
Для вывода двоичных значений в классе ShowBits определен метод show (), код которого приведен ниже. void show(long val) { long mask = 1; // сдвинуть значение 1 влево на нужную позицию mask <<= numbits-1; int spacer = 0; for(; mask != 0; mask >>>= 1) { if((val & mask) != 0) System.out.print("I"); else System.out.print("0"); spacer++; if((spacer % 8) == 0) { System.out.print(" "); spacer = 0; } } } System.out.println();
Обратите внимание на то, что данному методу передается один параметр типа long. Но это совсем не означает, что при вызове ему нужно всегда передавать значение типа long. Правила автоматического продвижения типов в Java допускают передавать методу show () любое целочисленное значение. А количество отображаемых битов определяется переменной numbits. Группы из 8 битов разделяются в методе show () пробелами. Это упрощает восприятие длинных двоичных комбинаций.
Ниже приведен весь исходный код программы из файла ShowBit sDemo. j ava./* Пример для опробования 5.3 Создание класса для отображения значений в двоичном виде.*/class ShowBits { int numbits; ShowBits(int n) { numbits = n; } void show(long val) { long mask = 1; // сдвинуть значения 1 влево на нужную позицию mask <<= numbits-1; int spacer = 0; for(; mask != 0; mask >>>= 1) { if ((val & mask) != 0) System.out.print ("1") ; else System.out.print("0"); spacer++; if((spacer % 8) == 0) { System.out.print(" "); spacer = 0; } } System.out.println(); }}// продемонстрировать класс ShowBitsclass ShowBitsDemo { public static void main(String args[]) { ShowBits b = new ShowBits(8); ShowBits i = new ShowBits(32); ShowBits li = new ShowBits(64); System.out.println("123 in binary: "); b.show(123); System.out.println("\n87987 in binary: "); i.show(87987); System.out.println("\n237658768 in binary: "); li.show(237658768); // можно также отобразить младшие разряды любого целого числа System.out.println("\nLow order 8 bits of 87987 in binary: "); b.show(87987); }}