Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на Java.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
3.45 Mб
Скачать

Тема 1.10 Преобразование типов.

Java запрещает смешивать в выражениях величины разных типов, однако при числовых операциях такое часто бывает необходимо. Различают повышающее (разрешенное, неявное) преобразование и понижающее приведение типа.

Повышающее преобразование осуществляется автоматически по следующему правилу (рис. 1.34 ). Серыми стрелками обозначены преобразования, при которых может произойти потеря точности.

Рисунок  1.34 – Преобразование типов

Преобразования между типами, несоединенными стрелками, неявно запрещены. Программист, проводя явное преобразование, берет ответственность за корректность преобразования на себя. Явное приведение типа имеет вид:

(целевой тип)значение

Для примера, рассмотрим программу, приведенную в листинге 1.5 .

Листинг 1.5

public class Conversion {

public static void main(String[] args) {

byte b;

int i=257;

double d=323.142;

b=(byte)i;

i=(int)d;

b=(byte)d;

}

}

Задание:

Модифицируйте код программы так, чтобы видеть на консоли результаты приведения типов. Прокомментируйте результаты.

Арифметические операции

К арифметическим операциям относятся:

  • сложение + (плюс);

  • вычитание - (дефис);

  • умножение * (звездочка);

  • деление / (наклонная черта – слэш);

  • взятие остатка от деления (деление по модулю) % (процент);

  • инкремент (увеличение на единицу) ++;

  • декремент (уменьшение на единицу) --.

Между сдвоенными плюсами и минусами нельзя оставлять пробелы. Сложение, вычитание и умножение целых значений выполняются как обычно, а вот деление целых значений в результате дает опять целое (так называемое "целое деление"), например, 5/2 даст в результате 2, а не 2.5 , а 5/(-3) даст -1. Дробная часть числа попросту отбрасы­вается, происходит усечение частного, т.к. в Java принято целочисленное деление. Это странное для математики правило естественно для программирования: если оба операнда имеют один и тот же тип, то и результат имеет тот же тип. Достаточно написать 5/2.0 или 5.0/2 или 5.0/2.0 и получим 2.5 как результат деления вещественных чисел.

Операция деление по модулю определяется так:

а % b = а - (а / b) * b

Например, 5%2 даст в результате 1 , а 5% (-3) даст, 2 , т.к.

5 = (-3)*(-1) + 2 , но (-5)%3 даст -2 , поскольку -5 = 3 * (-1) - 2.

Операции инкремент и декремент означают увеличение или уменьшение значения переменной на единицу и применяются только к переменным, но не к константам или выражениям, нельзя написать 5++ или (а + b)++ .

При постфиксной первой формe записи в выражении участвует старое значение переменной и только потом происходит увеличение или уменьшение ее значения. При второй форме записи (префиксной) сначала изменится переменная, и ее новое значение будет участвовать в выражении.

Например,k=10000; (k++) + 5 даст в результате 10005 , а переменная k примет значение 10001 . Но в той же исходной ситуации (++k) + 5 даст 10006, а переменная k станет равной 10001.

Операции сравнения

В языке Java шесть обычных операций сравнения целых чисел по величине:

  • больше >;

  • меньше <;

  • больше или равно >=;

  • меньше или равно <=;

  • равно ==;

  • не равно !=.

Сдвоенные символы записываются без пробелов, их нельзя переставлять местами, запись => будет неверной.

Результат сравнения будет иметь логическое значение: true для выражения 3 != 5 ; или false , например, для 3 == 5.

Для записи сложных сравнений следует использовать логичес­кие операции. Например, в вычислениях часто приходится делать проверки вида а < х < b. Подобная запись на языке Java приведет к сообщению об ошибке, поскольку первое сравнение а<х даст true или false, a Java не знает, больше это, чем b, или меньше. В данном случае следует написать выражение (а<х) && (х<b), причем здесь скобки можно опустить, написав а<х && х<b.

Побитовые операции

Наряду с арифметическими, логическими операторами и операторами сравнения, которые используются наиболее часто, Java предоставляет также побитовые операторы, которые позволяют расширить сферу использования данного языка. Побитовые операторы могут быть применены к значениям типа long, int, short, char и byte. Над типами boolean, float и double, а также над классами эти операции выполнять нельзя. Термин "побитовые" указывает на то, что операции из данной группы используются в основном для проверки, установки и переключения отдельных разрядов числа. Эти операции чрезвычайно важны для решения задач системного программирования, в которых необходимо анализировать данные, полученные с устройства, или сформировать значения, передаваемые на устройство.

  • побитовая операция AND &;

  • побитовая операция OR |;

  • побитовая операция XOR ^;

  • сдвиг вправо >>;

  • беззнаковый сдвиг вправо >>>;

  • сдвиг влево <<;

  • дополнение до единицы (унарная операция NOT) ~.

Выполнение операций AND, OR, XOR и NOT

Операции AND, OR, XOR и NOT осуществляют соответственно операторы &, |, ^ и ~. Они выполняют те же действия, что и эквивалентные им логические операторы, &&, ||, . Различие состоит в том, что побитовые операции выполняются над отдельными разрядами числа. В приведенной ниже таблице 7 показан результат выполнения каждого оператора над отдельными битами.

Таблица 1.7 – Побитовые операции

A

B

A&B

A|B

A^B

~A

0

0

0

0

0

1

1

0

0

1

1

0

0

1

0

1

1

1

1

1

1

1

0

0

Как правило, побитовая операция AND используется для сброса отдельных разрядов. Любой бит, значение которого равно нулю, хотя бы в одном из двух операндов будет равен нулю и в результирующем значении. Например:

1 1 0 1 0 0 1 1

& 1 0 1 0 1 0 1 0

____________

1 0 0 0 0 0 1 0

Использование оператора &.

В Unicode и ASCII коды букв нижнего Регистра отличаются от кодов букв верхнего регистра на 32. Таким образом, Для того, чтобы преобразовать символы нижнего регистра в верхний регистр, достаточно сбросить шестой бит.

Поскольку на символьный тип данных отводится 16 бит, то нужно в 16-битов числе в двоичном представлении сбросить 6-й бит. Для этого нужно число 1111111111011111 преобразовать в 10-ю систему счисления (65503) и использовать в операции AND.

Напишем программу перевода буквы нижнего регистра в верхний регистр путем сброса шестого бита кода символа.

Листинг 1.6

//Перевод букв в верхний регистр

class UpCase {

public static void main(String[] args) {

char ch;

for (int i = 0; i < 10; i++) {

ch = (char) ('a' + i);

System.out.print(ch);

//Данное выражение сбрасывает шестой бит

ch = (char) ((int) ch & 65503);

// Теперь в ch содержится

// код символа верхнего

// регистра

System.out.print(ch + " ");

}

}

}

Оператор AND удобен также в том случае, когда вам надо определить, установлен ли или сброшен некоторый бит числа. Например, приведенное ниже выражение определяет, установлен ли четвертый бит в переменной status.

if(status & 8) System.out.println(" bit 4 is on");

В данном случае число 8 использовано потому, что в его двоичном представлении (1000) установлен только четвертый бит. Таким образом, в выражении if значение true будет получено только тогда, когда четвертый бит значения, содержащегося в переменной status, также установлен. Подобный подход можно применить для преобразования значения типа byte в двоичный формат.

Листинг 1.7

import java.util.Scanner;

//Отображение битов в составе байта

public class ShowBits {

public static void main(String[] args) {

byte val = 0;

Scanner sc = new Scanner(System.in);

System.out.println("Введите число типа byte:12 ");

if (sc.hasNextByte()) {

val = sc.nextByte();

}

for (int t = 128; t > 0; t = t / 2) {

if ((val & t) != 0) {

System.out.print("1 ");

} else {

System.out.print("0 ");

}

}

}

}

В цикле for последовательно проверяется каждый бит переменной val; для чтобы определить, установлен ли бит, используется операция AND. Если бит установлен, отображается цифра 1, в противном случае выводится цифра 0.

Побитовая операция OR выполняет действия, противоположные операции AND и используется для установки битов. Любой бит, значение которого равно хотя бы в одном из двух операндов, будет равен единице и в результирующем значении. Оператор OR можно использовать для преобразования символов верхнего регистра в нижний регистр.

Задание:

Напишите программу для преобразования символов верхнего регистра в нижний регистр.

Операция XOR дает результат, в котором конкретный бит установлен в том и только в том случае, когда соответствующие биты в двух операндах имеют разные значения. Ниже приведен пример выполнения операции XOR.

Операция XOR имеет одну интересную особенность, которая позволяет очень просто кодировать сообщения. Если выполнить данную операцию над некоторыми числами X и Y, a затем снова выполнить операцию XOR над результирующим, значением и числом Y, то мы снова получим число X. Таким образом, при выполнении приведенных ниже двух команд R2 получит то же значение, которое имеет x

R1 = X ^ Y;

R2 = R1 ^ Y;

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

Листинг 1.8

// Использование операции XOR для шифрования и дешифровки сообщений class Encode {

class Encode {

public static void main(String args[]) {

String msg = "This is a test";

String encmsg = "";

String decmsg = "";

int key = 88;

System.out.print("Original message: ");

System.out.println(msg);

// Кодирование сообщения

for (int i = 0; i < msg.length(); i++) {

encmsg = encmsg + (char) (msg.charAt(i) ^ key);

}

System.out.print("Encoded message: ");

System.out.println(encmsg);

// Декодирование сообщения

for (int i = 0; i < msg.length(); i++) {

decmsg = decmsg + (char) (encmsg.charAt(i) ^ key);

}

System.out.print("Decoded message: ");

System.out.println(decmsg);

}

}

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

Операция дополнения (NOT) инвертирует все биты операнда. Например, если некоторая целочисленная переменная А содержит значение, двоичное представление которого равно 10010110, результатом выполнения выражения ~A будет набор битов 01101001.

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

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

Таблица 1.8 – Операторы сдвига

<<

Сдвиг влево

>>

Сдвиг вправо

>>>

Беззнаковый сдвиг вправо

Формат записи этих операторов приведен ниже.

значение << число_позиций

значение >> число_позиций

значение >>> число_позиций

Здесь слева от оператора задается значение, подлежащее сдвигу, а справа – число позиций, на которые производится сдвиг.

При сдвиге влево освободившиеся младшие биты заполняются нулями. При сдвиге вправо все происходит несколько сложнее. Как вы знаете, признаком отрицательного целого числа является единица в старшем бите, поэтому при обычном сдвиге вправо старший (знаковый) разряд дублируется. Если число положительное, то в него записывается нуль, если отрицательное – единица.

Помимо сохранения знакового разряда, необходимо помнить еще об одной особенности. Отрицательные числа в языке Java (как, впрочем, и в других языках) представляются как дополнение до двух. Чтобы преобразовать положительное число в отрицательное, его надо инвертировать, а к полученному значению прибавить единицу. Таким образом, значение -1 представляется двоичной последовательностью 11111111. Сдвинув это значение вправо на любое число позиций, мы снова получим -1!

Если вы не хотите, чтобы при сдвиге вправо сохранялся знаковый разряд, можете использовать беззнаковый сдвиг вправо (оператор >>>), при этом освободившиеся старшие разряды всегда будут заполняться нулями. Беззнаковый сдвиг удобно использовать для обработки значений, не являющихся числами, например кодов состояния.

При любом сдвиге биты теряются. Циклический сдвиг в языке Java не поддерживается, и нет возможности восстановить потерянные разряды.

Ниже приведен код программы, которая демонстрирует эффект от использования операторов сдвига. Целочисленное значение 1 представляется набором битов, в которых лишь младший равен 1. К этому значению восемь раз применяется операция сдвига влево. После каждого сдвига на экран выводится восемь младших разрядов числа. Затем единица устанавливается в восьмой позиции и производятся сдвиги вправо.

Выполняя сдвиг над значениями byte и short, необходимо соблюдать осторожность, поскольку исполняющая система Java автоматически преобразует в тип int, а лишь затем выполняет необходимые вычисления. Например, вы сдвинете вправо значение типа byte, то оно будет сначала преобразовано в int. Результат сдвига будет также иметь тип int. Обычно такое преобразование не влечет за собой никаких последствий. Однако если вы попытаетесь сдвинуть отрицательное значение, то при преобразовании в тип int старшие биты будут заполнены единицами. Это оправдано при обычном сдвиге вправо, но при беззнаковом сдвиге в старшем разряде будет обнаружена неожиданная единица. Лишь после двадцати четырех сдвигов появятся нулевые значения.

Варианты записи побитовых операций

Для всех побитовых операций предусмотрена сокращенная запись, подобная сокращенной записи логических и арифметических операций. Например, приведенные ниже две строки кода эквиваленты. В каждой из них выполняется опе­рация XOR над значением переменной x и числом 127.

x = x ^ 127;

x ^= 127;

Задачи

  1. В переменной n хранится двузначное число. Создайте программу, вычисляющую и выводящую на экран сумму цифр n.

  2. В переменной n хранится трёхзначное число. Создайте программу, вычисляющую и выводящую на экран сумму цифр n.

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

  4. В переменных q и w хранятся два натуральных числа. Создайте программу, выводящую на экран результат деления q на w с остатком. Пример вывода программы (для случая, когда в q хранится 21, а в w хранится 8):

21 / 8 = 2 и 5 в остатке