Главная страница

АБОБА. Справочник по программированию на Java Методическое пособие


Скачать 242.41 Kb.
НазваниеСправочник по программированию на Java Методическое пособие
АнкорАБОБА
Дата20.02.2022
Размер242.41 Kb.
Формат файлаdocx
Имя файла12642_java_method_1.docx
ТипСправочник
#368066
страница18 из 67
1   ...   14   15   16   17   18   19   20   21   ...   67

Сдвиг вправо без учета знака


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

Однако иногда это нежелательно. Например, при выполнении сдвига вправо в какомлибо значении, которое не является числовым, использование дополнительных знаковых разрядов может быть нежелательным. Эта ситуация часто встречается при работе со значениями пикселей и графическими изображениями. Как правило, в этих случаях требуется сдвиг нуля в позицию старшего бита независимо от его первоначального значения. Такое действие называют сдвигом вправо без учета знака. Для его выполнения используют операцию сдвига вправо без учета знака 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
1   ...   14   15   16   17   18   19   20   21   ...   67


написать администратору сайта