KnigaRead.com/

Брюс Эккель - Философия Java3

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Брюс Эккель, "Философия Java3" бесплатно, без регистрации.
Перейти на страницу:

Восьмеричное представление (по основанию 8) обозначается начальным нулем в записи числа, состоящего из цифр от 0 до 7. Для литеральной записи чисел в двоичном представлении в Java, С и С++ поддержки нет. Впрочем, при работе с шестнадцатеричныыми и восьмеричными числами часто требуется получить двоичное представление результата. Задача легко решается методами static toBinaryString() классов Integer и Long.

Экспоненциальная запись

Экспоненциальные значения записываются, по-моему, очень неудачно: 1.39e-47f. В науке и инженерном деле символом е обозначается основание натурального логарифма, равное примерно 2,718. (Более точное значение этой величины можно получить из свойства Math.E.) Оно используется в экспоненциальных выражениях, таких как 1,39хе-47, что фактически значит 1,39х2,718-47. Однако во время изобретения языка FORTRAN было решено, что е будет обозначать «десять в степени», что достаточно странно, поскольку FORTRAN разрабатывался для науки и техники и можно было предположить, что его создатели обратят внимание на подобную неоднозначность1. Так или иначе, этот обычай был перенят в С, С++, а затем перешел в Java. Таким образом, если вы привыкли видеть в е основание натурального логарифма, вам придется каждый раз делать преобразование в уме: если вы увидели в Java выражение 1.39e-43f, на самом деле оно значит 1,39х10~43.

Если компилятор может определить тип автоматически, наличие завершающего суффикса типа не обязательно. В записи

long пЗ = 200;

не существует никаких неясностей, и поэтому использование символа L после значения 200 было бы излишним. Однако в записи

float f4 = le-43f; // десять в степени

компилятор обычно трактует экспоненциальные числа как double. Без завершающего символа f он сообщит вам об ошибке и необходимости использования приведения для преобразования double к типу float.

Поразрядные операторы

Поразрядные операторы манипулируют отдельными битами в целочисленных примитивных типах данных. Результат определяется действиями булевой алгебры с соответствующими битами двух операндов.

Эти битовые операторы происходят от низкоуровневой направленности языка С, где часто приходится напрямую работать с оборудованием и устанавливать биты в аппаратных регистрах. Java изначально разрабатывался для управления телевизионными приставками, поэтому эта низкоуровневая ориентация все еще была нужна. Впрочем, вам вряд ли придется часто использовать эти операторы.

Поразрядный оператор И (&) заносит 1 в выходной бит, если оба входных бита были равны 1; в противном случае результат равен 0. Поразрядный оператор ИЛИ (|) заносит 1 в выходной бит, если хотя бы один из битов операндов был равен 1; результат равен 0 только в том случае, если оба бита операндов были нулевыми. Оператор ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR, л) имеет результатом единицу тогда, когда один из входных битов был единицей, но не оба вместе. Поразрядный оператор НЕ (~, также называемый оператором двоичного дополнения) является унарным оператором, то есть имеет только один операнд. Поразрядное НЕ производит бит, «противоположный» исходному — если входящий бит является нулем, то в результирующем бите окажется единица, если входящий бит — единица, получится ноль.

Поразрядные операторы и логические операторы записываются с помощью одних и тех же символов, поэтому полезно запомнить мнемоническое правило: так как биты «маленькие», в поразрядных операторах используется всего один символ.

Поразрядные операторы могут комбинироваться со знаком равенства =, чтобы совместить операцию и присвоение: &=, |= и л= являются допустимыми сочетаниями. (Так как ~ является унарным оператором, он не может использоваться вместе со знаком =.)

Тип boolean трактуется как однобитовый, поэтому операции с ним выглядят по-другому. Вы вправе выполнить поразрядные И, ИЛИ и ИСКЛЮЧАЮЩЕЕ ИЛИ, но НЕ использовать запрещено (видимо, чтобы предотвратить путаницу с логическим НЕ). Для типа boolean поразрядные операторы производят тот же эффект, что и логические, за одним исключением — они не поддерживают ускоренного вычисления. Кроме того, в число поразрядных операторов для boolean входит оператор ИСКЛЮЧАЮЩЕЕ ИЛИ, отсутствующий в списке логических операторов. Для булевых типов не разрешается использование операторов сдвига, описанных в следующем разделе.

Операторы сдвига

Операторы сдвига также манипулируют битами и используются только с примитивными целочисленными типами. Оператор сдвига влево («) сдвигает влево операнд, находящийся слева от оператора, на количество битов, указанное после оператора. Оператор сдвига вправо (») сдвигает вправо операнд, находящийся слева от оператора, на количество битов, указанное после оператора. При сдвиге вправо используется заполнение знаком: при положительном значении новые биты заполняются нулями, а при отрицательном — единицами. В Java также поддерживается беззнаковый сдвиг вправо »>, использующий заполнение нулями: независимо от знака старшие биты заполняются нулями. Такой оператор не имеет аналогов в С и С++.

Если сдвигаемое значение относится к типу char, byte или short, эти типы приводятся к int перед выполнением сдвига, и результат также получится int. При этом используется только пять младших битов с «правой» стороны. Таким образом, нельзя сдвинуть битов больше, чем вообще существует для целого числа int. Если вы проводите операции с числами long, то получите результаты типа long. При этом будет задействовано только шесть младших битов с «правой» стороны, что предотвращает использование излишнего числа битов.

Сдвиги можно совмещать со знаком равенства («=, или »=, или »>=). Именующее выражение заменяется им же, но с проведенными над ним операциями сдвига. Однако при этом возникает проблема с оператором беззнакового правого сдвига, совмещенного с присвоением. При использовании его с типом byte или short вы не получите правильных результатов. Вместо этого они сначала будут преобразованы к типу int и сдвинуты вправо, а затем обрезаны при возвращении к исходному типу, и результатом станет -1. Следующий пример демонстрирует это:

//: operators/URShi ft java // Проверка беззнакового сдвига вправо, import static net.mindview.util Print *;

public class URShift {

public static void main(String[] args) { int i = -1;

print(Integer.toBinaryString(i)); i »>= 10;

print(Integer.toBinaryString(i)), long 1 = -1;

print(Long.toBinaryString(l)); 1 »>= 10;

print(Long.toBinaryString(l)); short s = -1;

printdnteger toBinaryString(s)); s »>= 10;

pri nt(Integer.toBi na ryStri ng(s)), byte b = -1;

printdnteger toBinaryString(b)); b »>= 10;

pri nt(Integer.toBi na ryString(b)); b = -1;

pri nt(Integer.toBi na rySt ring(b)), pri nt (I nteger. toBi narySt ri ng( b»>10));

}

} /* Output; 11111111111111111111111111111111 1111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111 11111111111111111111111111111111 11111111111111111111111111111111 11111111111111111111111111111111 11111111111111111111111111111111 1111111111111111111111

В последней команде программы полученное значение не приводится обратно к Ь, поэтому получается верное действие.

Следующий пример демонстрирует использование всех операторов, так или иначе связанных с поразрядными операциями:

//; operators/BitManipulation.java // Использование поразрядных операторов, import java.util.*;

import static net.mindview.util Print.*;

public class BitManipulation {

public static void main(String[] args) { Random rand = new Random(47);

int i = rand nextlntO, int j = rand.nextlntO. printBinarylntC'-l", -1); printBinarylntC'+l", +1); int maxpos = 2147483647; printBinaryInt("макс положит.", maxpos); int maxneg = -2147483648; printBinarylntC'MaKc отрицат.". maxneg); printBinarylntC'i". i); printBinaryInt("~i", ~i); printBinaryInt("-i", -i); printBinarylntC'j", j), printBinarylntC'i & j". i & j), printBinarylntC'i | j", i | j); printBinarylntC'i A j". i A j); printBinarylntC'i « 5", i «5); printBinarylntC'i » 5", i » 5): printBinarylntC'M) » 5", (~i) » 5); printBinarylntC'i »> 5", i »> 5); printBinarylntC'M) »> 5", (~i) »> 5);

long 1 = rand.nextLongO; long m = rand.nextLongO; printBinaryLong("-lL", -1L); printBinaryLong("+lL", +1L): long 11 = 9223372036854775807L, printBinaryLongC'MaKC. положит.", 11); long 1 In = -9223372036854775808L; printBinaryLongC'MaKC. отрицат ", lln); printBinaryLongC'l", 1); printBinaryLong("~l", -1), printBinaryLong("-l", -1), printBi naryLongC'm", m), printBinaryLongC'l & m", 1 & m); printBinaryLongC'l | m", 1 | m); printBinaryLongC'l A m", 1 A m); printBinaryLongC'l « 5", 1 «5); printBinaryLongC'l » 5". 1 » 5); printBinaryLong("(~l) » 5", (~1) » 5). printBinaryLongC'l »> 5". 1 »> 5); printBi naryLongC'H) »> 5", (~1) »> 5); moni tor.expect("Bi tMani pulati on.out");

}

static void printBinaryInt(String s, int i) {

print(s + ". int: " + i + двоичное: n " + Integer toBinaryString(i));

}

static void printBinaryLong(String s, long 1) {

print(s + long: " + 1 + ", двоичное:п " + Long.toBinaryStringd));

}

} /* Output-

-1, int- -1, двоичное.

11111111111111111111111111111111 +1, int. 1, двоичное. 1

макс, положит . int- 2147483647. двоичное: 1111111111111111111111111111111

макс, отрицат., int: -2147483648, двоичное-10000000000000000000000000000000 i, int- -1172028779. двоичное: 10111010001001000100001010010101 ~i, int. 1172028778, двоичное. 1000101110110111011110101101010 -i, int. 1172028779. двоичное: 1000101110110111011110101101011 j. int: 1717241110, двоичное: 1100110010110110000010100010110 i & j, int- 570425364, двоичное: 100010000000000000000000010100 i | j, int. -25213033, двоичное. 11111110011111110100011110010111 i A j. int: -595638397, двоичное. 11011100011111110100011110000011 i «5, int: 1149784736, двоичное-1000100100010000101001010100000 i » 5, int -36625900, двоичное. 11111101110100010010001000010100 (~i) » 5, int 36625899, двоичное. 10001011101101110111101011 i »> 5, int. 97591828, двоичное. 101110100010010001000010100 (~i) »> 5, int- 36625899, двоичное. 10001011101101110111101011

*///.-

Два метода в конце, printBinaryInt() и printBinaryl_ong(), получают в качестве параметров, соответственно, числа int и long и выводят их в двоичном формате вместе с сопроводительным текстом. Вместе с демонстрацией поразрядных операций для типов int и long этот пример также выводит минимальное и максимальное значение, +1 и -1 для этих типов, чтобы вы лучше понимали, как они выглядят в двоичном представлении. Заметьте, что старший бит обозначает знак: 0 соответствует положительному и 1 — отрицательному числам. Результат работы для типа int приведен в конце листинга

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*