Сдвиг влево

Операция сдвига влево, «, сдвигает все биты значения влево на указанное число позиций. Она имеет следующую общую форму:

значение « число

Здесь число — количество позиций, на которое нужно сдвинуть влево биты в значении значение. То есть операция « смещает влево биты указанного значения на количество позиций, указанных в число. При каждом сдвиге влево самый старший бит сдвигается за пределы допустимого диапазона (и утрачивается), а ноль дописывается справа. Это означает, что при применении операции сдвига влево к операнду типа int биты утрачиваются, как только они сдвигаются за пределы 31 позиции. Если операнд имеет тип long, биты теряются после сдвига за пределы 63 позиции.

Автоматическое повышение типа, выполняемое в среде Java, приводит к непредвиденным результатам при выполнении сдвига в значениях типа byte и short. Как вы уже знаете, тип значений byte и short повышается до int при вычислении выражений. Более того, результат вычисления такого выражения также имеет тип int. Это означает, что результатом выполнения сдвига влево значения типа byte или short будет значение типа int, и сдвинутые влево биты не будут отброшены до тех пор, пока они не будут сдвинуты за пределы 31 позиции. Более того, при повышении до типа int отрицательное значение типа byte или short получит дополнительный знаковый разряд. Следовательно, старшие биты будут заполнены единицами. Поэтому выполнение операции сдвига влево применительно к значению типа byte или short предполагает необходимость отбрасывания старших байтов результата типа int. Например, при выполнении сдвига влево в значении типа byte вначале будет осуществляться повышение типа значения до int, и лишь затем сдвиг. Это означает, что для получения требуемого сдвинутого значения типа byte необходимо отбросить три старших байта результата. Простейший способ достижения этого — обратное приведение результата к типу byte. Следующая программа демонстрирует эту концепцию.

// Сдвиг влево значения типа byte.
class ByteShift {
public static void main(String args[]) {
byte a = 64, b;
int i;
i = a « 2;
b = (byte) (a « 2) ;
*-+ System.out.println("Первоначальное значение a: " + a);+
System.out.println("i and b: " + i + " " + b);
}
}

Эта программа генерирует следующий вывод:

Первоначальное значение а: 64
i and b: 256 0

Поскольку для выполнения вычислений тип переменной а повышается до int, сдвиг влево на две позиции значения 64 (0100 0000) приводит к значению i, равному 256 (1 0000 0000). Однако переменная b содержит значение, равное 0, поскольку после сдвига младший байт равен 0. Единственный единичный бит оказывается сдвинутым за пределы допустимого диапазона.

Поскольку каждый сдвиг влево на одну позицию, по сути, удваивает исходное значение, программисты часто используют это в качестве эффективной замены умножения на 2. Однако при этом следует соблюдать осторожность. При сдвиге единичного бита в старшую позицию (бит 31 или 63) значение становится отрицательным. Следующая программа демонстрирует это применение операции сдвига влево.

// Применение сдвига влево в качестве быстрого метода умножения на 2.
class MultByTwo {
public static void main(String args[]) {
int i;
int num = OxFFFFFFE;
for(i=0; i<4; i++) { num = num « 1;
System.out.println(num);
}
}
)

Программа генерирует следующий вывод:

536870908
1073741816
2147483632
-32

Начальное значение было специально выбрано таким, чтобы после сдвига влево на 4 позиции оно стало равным -32. Как видите, после сдвига единичного бита в позицию 31 число интерпретируется как отрицательное.