
- •Программирование на Java
- •Глава 1 Введение в java. Основы языка.
- •Тема 1.1 Язык программирования java.
- •Тема 1.2 Состав пакета Java2.
- •Тема 1.3 Настройка среды окружения.
- •Тема 1.4 Структура Java-программы.
- •Тема 1.5 Набор текста, запуск и компиляция простейшей программы.
- •Тема 1.6 Подробное рассмотрение кода простейшей программы.
- •Тема 1.7. Создание программы в разных средах разработки.
- •Тема 1.8 Лексические основы языка
- •Тема 1.9 Элементарные типы данных.
- •Тема 1.10 Преобразование типов.
- •Арифметические операции
- •Операции сравнения
- •Тема 1.11 Кoнсольный ввод с помощью класса java.Util.Scanner
- •Тема 1.12 Классы-оболочки
- •Тема 1.13 Автоупакока и автораспаковка.
- •Тема 1.14 Операторы
- •1.14.1 Блок
- •1.14.2 Условный оператор if
- •1.14.4 Оператор цикла while
- •1.14.5 Оператор цикла do-while
- •1.14.6 Оператор цикла for
- •1.14.7 Оператор continue и метки
- •1.14.8 Оператор break
- •1.14.9 Оператор варианта switch
- •Тема 1.15 Статический импорт
- •Тема 1.16 Класс Math
- •Задания
- •Тема 1.17 Псевдослучайные числа
- •Тема 1.18 Генерация случайных чисел
- •Тема 1.19 Массивы в Java
- •1.19.1 Объявление и заполнение массива
- •1.19.2 Сортировка массива
- •Сортировка выбором
- •Сортировка методом пузырька
- •1.19.3 Многомерные массивы
- •Задания
- •1.19.4 Нерегулярные массивы
- •Глава 2 классы
- •Тема 2.1 Основы классов
- •Тема 2.2 Общая форма класса
- •Тема 2.3 Объявление объектов
- •Тема 2.4 Более подробное рассмотрение операции new
- •Тема 2.5 Присваивание переменных объектных ссылок
- •Тема 2.6 Знакомство с методами
- •Тема 2.7 Возвращение значения из метода
- •Тема 2.8 Добавление метода, принимающего параметры
- •Тема 2.9 Конструкторы
- •Тема 2.10 Сборка мусора
- •Тема 2.11 Перегрузка методов
- •Тема 2.12 Перегрузка конструкторов
- •Тема 2.13 Использование объектов в качестве параметров
- •Тема 2.14 Более пристальный взгляд на передачу аргументов
- •Тема 2.16 Рекурсия
- •Тема 2.17 Введение в управление доступом
- •Тема 2.18 Ключевое слово static
- •Тема 2.19 Ключевое слово final
- •Тема 2.20 Аргументы переменной длины
- •Тема 2.21 Строки и числа
- •Тема 2.22 Нумерованные типы
- •Глава 3 наследование и интерфейсы
- •Тема 3.1 Основы наследования
- •Тема 3.2 Наследование и доступ к членам класса
- •Тема 3.3 Конструкторы и наследование
- •Тема 3.4 Использование ключевого слова super для вызова конструктора суперкласса
- •Тема 3.5 Использование ключевого слова super для доступа к членам суперкласса
- •Тема 3.6 Многоуровневая иерархия
- •Тема 3.7 Когда вызываются конструкторы
- •Тема 3.8 Объекты подклассов и ссылки на суперклассы
- •Тема 3.9 Переопределение методов
- •Тема 3.10 Переопределение методов и поддержка полиморфизма
- •Тема 3.11 Использование абстрактных классов
- •Тема 3.12 Использование ключевого слова final
- •Тема 3.13 Предотвращение переопределения методов
- •Тема 3.14 Предотвращение наследования
- •Тема 3.15 Класс Object
- •Тема 3.16 Интерфейсы
- •3.16.1 Объявление интерфейса.
- •3.16.2 Реализация интерфейсов
- •3.16.3 Использование ссылок на интерфейсы
- •3.16.4 Переменные в составе интерфейсов
- •3.16.5 Наследование интерфейсов
- •Тема 3.17 Пакеты и ограничение доступа
- •Тема 3.18 Внутренние классы
- •3.18.1 Внутренние (inner) классы
- •3.18.2 Вложенные (nested) классы
- •3.18.3 Анонимные (anonymous) классы
- •Глава 4 Обработка исключительных ситуаций
- •Тема 4.1 Исключения в Java
- •Тема 4.2 Типы исключений
- •Тема 4.3 Неперехваченные исключения
- •Тема 4.4 Ключевые слова try и catch
- •Тема 4.6 Ключевое слово throw
- •Тема 4.7 Ключевое слово throws
- •Тема 4.8 Ключевое слово finally
- •Ошибка при выполнении метода1 java.Lang.ArithmeticException: Demo
- •Тема 4.9 Потомки Exception или написание своих классов ошибок
- •Глава 5 Универсальные типы. КоллекциИ
- •Тема 5.1 Общие сведения об универсальных типах
- •Тема 5.2 Универсальный класс с двумя параметрами типа
- •Тема 5.3 Ограниченные типы
- •Тема 5.4 Использование групповых параметров
- •Тема 5.5 Универсальные методы
- •Тема 5.6 Универсальные интерфейсы
- •Тема 5.7 Ошибки неоднозначности
- •Тема 5.8 Ограничения универсальных типов
- •Тема 5.9 Краткий обзор коллекций
- •5.9.1 Класс ArrayList
- •5.9.2 Класс LinkedList
- •5.9.3 Класс HashSet
- •5.9.4 Класс TreeSet
- •5.9.5 Доступ к коллекции через итератор
- •5.9.6 Алгоритмы коллекций
- •Глава 6 jdbc (Java DataBase Connectivity) Тема 6.1 Драйверы, соединения и запросы
- •Тема 6.2 Простое соединение и простой запрос
- •Тема 6.2 Класс ResultSet
- •Тема 6.3 Метаданные
- •Тема 6.4 Подготовленные запросы
- •Глава 7 Swing и пользовательский интерфейс
- •Тема 7.1 Общие сведения о swing
- •Тема 7.2 Архитектура mvc
- •Тема 7.3 Контейнер и компоненты
- •Тема 7.4 Простая программа, использующая средства Swing
- •Тема 7.5 Поддержка событий
- •Тема 7.6 Использование кнопок и обработка событий
- •Тема 7.7 Краткие сведения о диспетчерах компоновки
- •Тема 7.8 Пример использования jdbc и swing вместе
Тема 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;
Задачи
В переменной n хранится двузначное число. Создайте программу, вычисляющую и выводящую на экран сумму цифр n.
В переменной n хранится трёхзначное число. Создайте программу, вычисляющую и выводящую на экран сумму цифр n.
В переменной n хранится вещественное число с ненулевой дробной частью. Создайте программу, округляющую число n до ближайшего целого и выводящую результат на экран.
В переменных q и w хранятся два натуральных числа. Создайте программу, выводящую на экран результат деления q на w с остатком. Пример вывода программы (для случая, когда в q хранится 21, а в w хранится 8):
21 / 8 = 2 и 5 в остатке