Вы находитесь на странице: 1из 301

Основы программирования

на Java

2019
Java – это высокоуровневый ОО язык программирования. В
основе концепции объектно-ориентированного
программирования лежит понятие объекта — некой сущности,
которая объединяет в себе поля (данные) и методы
(выполняемые объектом действия).
В современных объектно-ориентированных языках
используются три основных механизма:
1. Наследование - создание нового класса объектов путём
добавления новых элементов (методов). процесс перенимания
классом свойств (методов и полей) другого класса. С
использованием в Java наследования информация становится
управляемой в иерархическом порядке.
Класс, который наследует свойства другого класса, называется
подклассом (производным классом, наследующим классом), а
класс, свойства которого наследуются, известен как суперкласс
(базовый класс, родительский класс).
2. Инкапсуляция. Сокрытие детали реализации, которое
позволяет вносить изменения в части программы
безболезненно для других её частей, что существенно
упрощает сопровождение и модификацию ПО. Инкапсуляция
означает, что данные объекта недоступны его клиентам
непосредственно. Вместо этого они инкапсулируются —
скрываются от прямого доступа извне. Инкапсуляция
предохраняет данные объекта от нежелательного доступа,
позволяя объекту самому управлять доступом к своим данным.
3. Полиморфизм. При полиморфизме некоторые части (методы)
родительского класса заменяются новыми, реализующими
специфические для данного потомка действия. Таким образом,
интерфейс классов остаётся прежним, а реализация методов с
одинаковым названием и набором параметров различается.

Наиболее популярные языки программирования: С#, C++, Java, Delphi, VB.NET, Perl,
Python, JavaScript, Jscript.NET, Ruby, Ada, PHP.
Выполнение Java программ

Главная особенность технологии Java – программа


компилируется сразу в машинные коды, но не в команды какого-
то конкретного процессора, а в команды виртуальной машины
Java (Java Virtual Machine, JVM). JVM – это совокупность
команд вместе с системой их выполнения. Полное описание
команд и всех архитектуры JVM содержится в спецификации
виртуальной машины (Virtual Machine Specification, VMS).
Другая особенность Java – все стандартные функции,
вызываемые в программе, подключаются к ней только на этапе
выполнения, в не включаются в байт-коды (динамическая
компоновка).

То есть, написанную программу на любой платформе, можно


запускать на любой другой платформе, где есть установленная
виртуальная машина Java.
Другая особенность Java – все стандартные функции, вызываемые в
программе, подключаются к ней только на этапе выполнения, в не
включаются в байт-коды (динамическая компоновка).

То есть, написанную программу на любой платформе, можно запускать на


любой другой платформе, где есть установленная виртуальная машина
Java.

Набор необходимых программных инструментов для полного цикла


работы с этим языком программирования: компиляция, интерпретация,
отладки, включающий и богатую библиотеку классов. Этот набор
называется JDK – Java development kit.
Набор программ и классов JDK содержит:
- компилятор из исходного текста в байт-коды javac;
- интерпретатор java, содержащий реализацию JVM;
- программу генерации заголовочных файлов языка С для
создания «родных» методов javah;
- программу простора апплетов appletviewer. Заменяющую
браузер;
- отладчик jdb;
- программу архивации и сжатия jar;
Что такое JRE? Это набор программ и пакет классов, который
содержит всё необходимое для выполнения байт-кодов, в том
числе интерпретатор java и библиотеку классов. Это часть
JDK, не содержащая компиляторы, отладчики и другие
средства разработки. Именно Oracle JRE или его аналог,
присутствует в тех браузерах, которые умеют выполнять
программы на Java, в операционных системах и системах
управления базами данных.
Существенные особенности языка Java

1. Всякая программа, написанная на языке Java, представляет


собой один или несколько классов.
2. Начало класса отмечается служебным словом class, за
которым следует имя класса, которое должно быть выбрано по
определенным правилам. Все, что содержится в классе,
записывается в фигурных скобках и составляет тело класса.
3. Все действия в программе производятся с помощью
методов обработки информации, коротко говорят просто
метод. Методы используются в ООП вместо функций,
применяемых в процедурных языках.
4. Методы различаются по именам и параметрам. Один из
методов обязательно должен называться main, c него
начинается выполнение программы.
5. Как и положено функции, метод всегда выдает в результате
(возвращает) только одно значение, типа которого обязательно
указывается перед именем метода. Метод может и не
возвращать никакого значения, играя роль процедуры. Тогда
вместо типа возвращаемого типа записывается слово void.
6. После имени метода в скобках через запятую перечисляются
параметры метода. Для каждого параметра указывается его
типа и через пробел – имя. У метода main() только один
параметр, его тип – массив, состоящий из символов. Строка
символов – это встроенный в Java API тип String, в квадратных
скобках – признак массива. Имя параметра может быть
произвольным.
7. Перед типом возвращаемого методом значения могут быть
записаны модификаторы.
8. Всё что содержит метод, тело метода записывается в
фигурных скобках.
Язык Java различает строчные и прописные буквы, имена main, Main, MAIN
отличаются с точки зрения компилятора Java. Компилятор не «смотрит» на текст в
кавычках.

Существует важное соглашение:


- имена классов начинаются с прописной (заглавной) буквы; если имя содержит
несколько слов, то каждое слово начинается с прописной буквы;
- имена методов и переменных начинаются со строчной буквы; если имя содержит
несколько слов, то каждое следующее слово начинается с прописной буквы;
- имена констант записываются полностью прописными буквами; если имя состоит
из нескольких слов, то между ними ставится знак подчеркивания.
- имена должны быть «говорящими».
Комментарии в программе

В программу можно вставлять комментарии, которые компилятор не


будет учитывать – это очень удобно для пояснений хода программы.
- за двумя косыми чертами, написанными подряд без пробела между
ними, начинается комментарий, продолжающийся до конца строки. //
- За наклонной чертой и звездочкой /* начинается комментарий,
который может занимать несколько строк, до звездочки и наклонной
черты*/
- за наклонной чертой и двумя звёздочками /** начинается
комментарий, который может занимать несколько строк, до звездочки и
наклонной черты */. Из таких комментариев формируется
документация.
Константы

Целые константы можно записывать в четырех системах счисления:


- в привычной десятичной форме;
- в двоичной системе счисления, начиная с нуля и буквы b или B – 0b1001, 0B11011;
- В восьмеричной форме, начиная с нуля – 027, -0326 (в таких константах
недопустимо использовать цифры 8 и 9);
- в шестнадцатеричной форме, начиная с нуля и латинской буквы х или Х: 0хFF2D;
Действительные константы записываются только в десятичной системе счисления:
- с фиксированной точкой: 37.25;
- с плавающей точкой: 2.5е34, -0.345е-25 (можно писать прописную или строчную
букву Е).
Символы

Одиночные символы записываются в апострофах, чтобы отличить их от имен


переменных:
- печатные символы, записанные на клавиатуры, просто записываются в
апострофах: 'a', 'N';
- управляющие и специальные символы записываются в апострофах с обратным
слэшем, чтобы отличить их от обычных символов:
- '\n' – символ перевода строки LF;
- '\r' – символ возврата каретки CR;
- '\f’ – символ перевода страницы FF;
- '\b' – символ возврата на шаг BS;
- '\t' – символ горизонтальной табуляции HT;
- '\\' – обратная наклонная черта;
- '\»’ – кавычка;
- '\'' – апостроф;
Символы

Код любого символа с десятично кодировкой от 0 до 255 можно задать, записав не


более чем тремя цифрами в восьмеричной системе счисления в апострофах, после
обратного слэша – '\123’ – буква s и пр.

Код любого символа в кодировке Unicode набирается в апострофах после обратного


слеша и латинской буквы u четырьмя шестнадцатеричными цифрами – '\u0053’ –
буква s.

Символы хранятся в формате типа char.


Строки

Строки символов заключаются в кавычки. Управляющие символы и коды


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

“Это строка \n c переносом.”


«\”Зубило\ - Чемпион!’”
Строки символов нельзя начинать на одной строке, а заканчивать на другой.

Для строковых констант определена операция сцепления, обозначаемая плюсом –


например:
«Пример » + «сцепления строк»
Обратить внимание на пробел.
Имена

Имена переменных, классов, методов и др. объектов могут быть


простыми и составными. Имена (идентификаторы) в Java составляются
из букв и арабских цифр, причем первым символом не может быть
цифра. (2е3). Еще можно использовать символ подчеркивания.
Кроме того, нельзя использовать служебные слова как идентификатор
(void, class и пр.).
Составное имя – несколько идентификаторов, разделенных точками, без
пробелов (System.out.printIn).
Типы данных и операции

Все типы данных в Java делятся на две группы – примитивные типы и ссылочные
типы.
Ссылочные типы включают в себя массивы, классы, интерфейсы и перечислимый
тип.
Примитивных типов всего восемь – логический тип и семь числовых типов.
Числовые типы делятся на целые типы и вещественные типы.
Целых типов пять: byte, short, int, long, char.
Символы можно применять везде, где используется тип int, поэтому Java
причисляет char к целым типам.
2+'ж' – к двойке прибавляется кодировка буквы ж в Юникоде = \u0416=1046
2+1046=1048
2+”ж” – так как ж записана как строка, то произойдет склейка строк и получим 2ж.

Вещественных типов всего два – float и double.


Типы данных и операции
Тип Разрядность Диапазон

(байт)
byte 1 От -128 до 127
short 2 От -32768 до 32767

int 4 От -2147483648 до 2147483647


long 8 От -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807

char 2 От '\u0000' до '\uFFFF', в десятичной форме от 0 до 65535

float 4 байта 3,4х10-38<|x|<3,4x1038 (точность – 7-8 цифр в дробной части)

double 8 байтов 1,7х10-308<|x|<1,7x10308 (точноть – 17 цифр в дробной части)


Типы данных и операции

Из-за того, что по имени переменной невозможно определить


её тип, все переменные обязательно должны быть описаны
перед их использованием – записывается имя типа, затем
через пробел список имен переменных, относящихся к этому
типу. Имена в списке разделяются запятой. Для всех или
некоторых переменных можно указать начальные значения
после знака равенства, которыми могут служить любые
константные выражения того же типа.
Логический тип

Значения логического типа boolean возникают в результате


различных сравнений, вроде 2>3, и используются главным
образом в условных операторах и операторах циклов.
Логических значений всего два – true и false. Описание
переменных:
boolean b=true, bb=false, bool2;
Над логическими данными можно выполнять операции
присваивания, сравнение на равенство и неравенство b==bb
или b != bb.
Логические операции

В языке Java реализованы четыре логические операции:


- отрицание (NOT) - ! (обозначается воскл. знаком) – меняет значение
истинности;
- конъюнкция (и) (AND) - & (амперсанд) – на выходе истина, если
только оба операнда истинны;
- дизъюнкция (OR) - | (вертикальная черта) – на выходе ложь, только
если оба операнда ложны;
- исключающее или (XOR) - ^ (каре) – истина, только если значения
операндов различны.
Логические операции
 
Кроме перечисленных, есть еще две логические операции сокращенного вычисления:
 
- Сокращенное И (AND) - &&
- Сокращенное ИЛИ (OR) - ||
В этих операциях правый операнд вычисляется только если от него зависит результат операции, то
есть в сокращенном И правый операнд вычисляется только если левый операнд true, а в
сокращенном ИЛИ правый операнд вычисляется только если левый операнд false.

b1 b2 !b1 b1&b2 b1|b2 b1^b2


true true false true true false
true false false false true true
false true true false true true
false false true false false false
Операции над целыми типами

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


- сложение - +;
- вычитание - -;
- умножение - *
- деление - /
- взятие остатка от деления (деление по модулю) - %
- инкремент (увеличение на единицу) - ++
- декремент (уменьшение на единицу) ––
Операции над целыми типами

Деление целых значений в результате дает опять целое –


(целочисленное деление) – например, 5/2 даст значение 2, а не 2,5. То
есть если два операнда имеют один и тот же типа, то и результат имеет
этот же тип.

Если написать 5.0/2, то получим 2.5.


Операции над целыми типами

Инкремент и декремент можно применять только к переменным – к


константам и выражениям нельзя (5++ и (a+b)++).

Инкремент и декремент бывает префиксый и постфиксный –


k=999;
(k++)+5;
получим 1004
но
k=999;
(++k)+5;
получим 1005
Операции присваивания

Простая операция присваивания записывается знаком равенства =,


слева от которого стоит переменная, а справа – выражение, совместимое
с типом переменной.

Рассказать про механизм присваивания (в т.ч. присваивание


выражений).

Кроме простых операций присваивание есть еще 11 составных


операций присваивания: +=, -=, *=, /=, %=, &=, !=, ^=, <<=, >>=, >>>=.

x=(тип данных переменной х)(х операция а)


Условная операция

Эта операция имеет три операнда. Вначале записывается произвольное


логическое выражение (в результате его получается true или false), затем
знак вопроса, а потом два произвольных выражения, разделенных
двоеточием:
x>y?x-y:y-x
сначала выполняется логическое выражение – если тру, то выполняется
только первое выражение (второе – не выполняется), а если фолс – то
только второе (первое не выполняется) – можно не опасаться деления на
ноль.
Какой смысл операции x>0?x:-x
Что дает в результате операция x>y?x:y
Выражения

Из констант и переменных, операций над ними, вызовов методов и


скобок составляется выражение. Все элементы выражения должны быть
совместимы по типу. При вычислении выражения выполняются четыре
правила:
- Операции одного приоритета вычисляются слева направо: x+y+z
вычисляется так (x+y)+z. Исключение – операции присваивания
вычисляются справа налево x=y=z вычисляется x=(y=z).
- Левый операнд вычисляется раньше правого.
- Операнды полностью вычисляются перед выполнением операции.
- Перед выполнением составной операции присваивания значение левой
части сохраняется для использования в правой части.
Выражения
Пример:
int a=3, b=5;
Результатом b+(b=3) будет 8.
(b=3)+b результат будет 6.
b+=(b=3) будет 8, потому что вычисляется как первое из приведенных
выражений.
b+=a+=b+=7 – в результате получим ? 20.
А если записать в две строчки:
a+=b+=7;
b+=a;
получим 27, так как во втором выражении уже будет новое значение
переменной b.
Приоритет операций

В порядке убывания приоритета (операции на одной строке имеют


одинаковый приоритет):
1. Постфиксные операции ++ и --;
2. Префиксные операции ++ и --, дополнение – и отрицание !;
3. Приведение типа (тип);
4. Умножение *, деление / и взятие остатка %;
5. Сложение + и вычитание-;
6. Сдвиги <<, >>, >>>;
7. Сравнение <, >, <=, >=;
Приоритет операций

8. Сравнение ==, !=.


9. Побитовая коньюнкция &;
10.Побитовое исключающее ИЛИ ^;
11.Побитовая дизьюнкция |;
12.Коньюнкция &&;
13.Дизьюнкция ||;
14.Условная операция ?:;
15.Присваивания =, +=, -=, *=, /=, %=, &=, ^=, !=, сдвиги.
Операторы

Всякий язык программирования должен иметь средства записи


алгоритмов (операторов). Набор операторов языка Java включает:
- операторы описания переменных и других объектов;
- операторы-выражения;
- операторы присваивания;
- условный оператор if;
- три оператора цикла while, do-while, for;
- оператор варианта switch;
- оператора варианта break, continue и return;
- блок, выделяемый скобками {};
- пустой оператор – точка с запятой.
Блок

Блок содержит в себе нуль или несколько операторов с целью


использовать их как один оператор в тех местах, где по правилам языка
можно записать только один оператор. Например {x=5; y=7;}
Блоки используются для ограничения области действия переменных, а
иногда просто для улучшения читаемости текста программы.
Операторы присваивания

Точка с запятой в конце любой операции присваивания превращает её в


оператор присваивания. Побочное действие операции – присваивание –
становится в операторе основным.
Разница между операцией присваивания и оператором присваивания
носит лишь теоретический характер.
Условный оператор

Условный оператор предназначен для организации разветвлений в программе. Синтаксис:

if (логическое выражение) {оператор1} else {оператор2};

Если логическое выражение – true, то вычисляется оператор1, а оператор2 не вычисляется. После


этого выполняется то, что следует за оператором if. Если же логвыр – false, то действует оператор2,
при этом оператор1 не выполняется.

Условный оператор может быть без ветви else

if (x<y) then {
x=10; /* при необходимости можно использовать несколько операторов, но только в блоке фигурных
скобок! */
}
Условный оператор

Очень часто одним из операторов является опять-таки условный оператор.

if (x>1) {
y=100
} else if (x<10) {
y=10:
} else {
y=1;
}
Условный оператор

Возникает вопрос – к какому именно оператору if относится ветвь else? Для языка
Java, как и для большинства языков, ветвь else относится к ближайшему слева
условию if, не имеющему своей ветви else. Изменить этот порядок можно с
помощью блока.

int ind=5, x=100;


if (ind>=100) if (ind<=20) x=0; else x=1; на выходе будет 100.

а если

if (ind>=100) {if (ind<=20) x=0;} else x=1; на выходе будет 1


Операторы цикла

Синтаксис оператора while:

while (логическое_выражение) {оператор;}

Вначале вычисляется логическое выражение, и если оно true, то


выполняется тело оператора. Если false, то цикл не выполняется.

while (x>0)
{
y+=2;
}
Операторы цикла

Второй оператор цикла do-while:

do {оператор} while (логическое_выражение);

Данный цикл выполняется как минимум один раз, затем если


логическое выражение – true – выполнение цикла повторяется, если
false – то выполнение цикла прекращается.

do
{if (x>0) x-=1;}
while (x>0);
Операторы цикла

Оператор for;

for (список выражений1; логвыр; список выражений2) {оператор;}

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


{
if (x!=2) {x=2;}
}
Операторы цикла

Оператор continue;

Вызывает безусловный переход к следующей итерации цикла.

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


{
if (x==2) {continue;}
if (x!=2) {x=2;}
}
Операторы цикла

Оператор break;

Вызывает немедленное прекращение цикла.

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


{
if (x==2) {continue;}
if (x!=2) {x=2;}
if(x==3) {break;}
}
Операторы цикла

Бесконечный цикл

В некоторых случаях допускается использования безусловного цикла, С


указанием обязательного выхода из цикла внутри оператора.

while (true)
{
if (x==2) {continue;}
if (x!=2) {x++;}
if(x==3) {break;}
}
Оператор варианта

Оператор варианта switch организует разветвление по нескольким направлениям.


Каждая ветвь отмечается константой или константным выражением какого-либо
целого типа (кроме long) и выбирается, если значение определенного выражения
совпадет с этой константой.

switch (логическое_выражение) {
case коснтвыр1: оператор1;
case коснтвыр2: оператор2;
case коснтвыр3: оператор3;
….
case коснтвырN: операторN;
default: операторDef;
Оператор варианта

Все константные выражения вычисляются на этапе компиляции и должны


отличаться друг от друга по значению. Затем вычисляется выражение, записанное в
круглых скобках. Если оно совпадает с одной из констант, то выполняется оператор,
отмеченный этой константой. Затем выполняются все следующие операторы,
включая и оператор Def и работа оператора варианта заканчивается.
Если же ни одна константа не равна значения выражения, то выполняется оператор
Def и все следующие за ним операторы. Поэтому ветвь default должна быть
записана последней. Ветвь default может отсутствовать, тогда оператор варианта
вообще ничего не делает.
Чаще всего требуется выполнить только одну ветвь – в этом случаем используется
оператор break, сразу же прекращающий выполнение оператора switch.
Оператор варианта

С другой стороны может понадобится выполнить один и тот же оператор в


нескольких ветвях case. В этом случае ставим несколько меток case подряд.

switch (dayOf Week) {


case 1: case 2: case 3: case 4: case 5:
System.out.println(“Рабочий день»); break;
case 6: case 7:
System.out.println(“Выходной день»); break;
default:
System.out.println(“Неправильно задан день недели»);
}
Массивы

Массив – это совокупность переменных одного типа, хранящих свои значения в


смежных ячейках оперативной памяти. Массивы в Java относятся к ссылочным
типам и описываются своеобразно, но характерно для ссылочных типов. Описание
производится в три этапа.
Первый этап – объявление. На этом этапе определяется только переменная типа
ссылка на массив, содержащая тип массива. Для этого записывается имя типа
элементов массива, квадратными скобками указывается, что объявляется ссылка на
массив, а не простая переменная и перечисляются имена переменных ссылочного
типа, например

double[] a, b;
квадратные скобки можно и переставлять сразу после имени, если это нужно:
int i=0, ar[], k=-1;
Массивы

Второй этап – определение. На этом этапе указывается количество элементов


массива, называемое его длиной, выделяется место для массива в оперативной
памяти, переменная-ссылка получает адрес массива. Все эти действия производятся
еще одной операцией языка Java – операцией new тип, выделяющей участок в
оперативной памяти для объекта, указанного в операции типа, и возвращающей в
качестве результата адрес этого участка.
Например,
a=new double[5];
b=new double[100];
ar=new int[50];
При этом все элементы массива получают нулевые значения.
Индексы массивов всегда начинаются с 0. Массив состоящий из пяти переменных
не имеет элемента a[5], но имеет элемент a[0].
Массивы

Третий этап – инициализация. На этом этапе элементы массива


получают начальные значения. Например:

a[0]=0.01; a[1]=-3.4; a[2]=2.09;


for (int i=0; i<100; i++) b[i]=1.0/i;
Массивы

Первые два этапа можно совместить:


double[] a=new double[5], b=new double [100];
int i=0, ar[]=new int[50], k=1;

Можно сразу задать и начальные значения, записав их в фигурных скобках через


запятую в виде констант или константных выражений. При этом даже
необязательно указывать количество элементов массива, оно будет равно
количеству начальных значений.
double[] a={0.01,-3.34,2.85,4.5,-6.7};

Можно совместить второй и третий этап:


a=new double[] {0.01,-3.34,2.85,4.5,-6.7}
Массивы

Ссылка на массив не является частью описанного массива, её можно перебросить


на другой массив того же типа операцией присваивания. Например, после
присваивания a=b обе ссылки a и b будут указывать на один и тот же массив из 100
вещественных переменных типа double и содержит один и тот же адрес. Кроме
простой операции присваивания со ссылками можно производить еще только
сравнение на равенство (a==b) и неравенство (a!=b). При этом сопоставляются
адреса, содержащиеся в ссылках – мы можем узнать, не ссылаются ли они на один и
тот же массив.
Кроме ссылки на массив для каждого массива автоматически определяется целая
константа с одним и тем же именем length. Её значение равно длине массива. Для
массива имя этой константы уточняется именем массива через точку – a.length.
Многомерные массивы

Элементами массивов в Java могут быть массивы. Объявляются:


char [][] c;
или
char[] c[];
или
char c[][];

Затем определяем внешний массив и его размерность:


с= new char[3][]; массив состоит из трех элементов-массов. Определяем элементы-массивы:
c[0]=new char[2];
c[1]=new char[4];
c[2]=new char[3];

После этих определений c.length равна 3, с[0].length равна 2.


Сортировка массивов

Свойства и классификация
• Устойчивость (англ. stability) — устойчивая сортировка не меняет взаимного
расположения элементов с одинаковыми ключами.
• Естественность поведения — эффективность метода при обработке уже
упорядоченных или частично упорядоченных данных. Алгоритм ведёт себя
естественно, если учитывает эту характеристику входной последовательности и
работает лучше.
• Использование операции сравнения. Алгоритмы, использующие для сортировки
сравнение элементов между собой, называются основанными на сравнениях. Для
специальных случаев (типов данных) существуют более эффективные алгоритмы.
Сортировка массивов

Важным свойством алгоритма является его сфера применения. Здесь основных


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

• Внешняя сортировка оперирует запоминающими устройствами большого


объёма, но не с произвольным доступом, а последовательным (упорядочение
файлов), то есть в данный момент «виден» только один элемент, а затраты на
перемотку по сравнению с памятью неоправданно велики. Это накладывает
некоторые дополнительные ограничения на алгоритм и приводит к специальным
методам упорядочения, обычно использующим дополнительное дисковое
пространство. Кроме того, доступ к данным во внешней памяти производится
намного медленнее, чем операции с оперативной памятью.
o Доступ к носителю осуществляется последовательным образом: в каждый
момент времени можно считать или записать только элемент, следующий за
текущим.
o Объём данных не позволяет им разместиться в ОЗУ.
Алгоритмы устойчивой сортировки

• Сортировка пузырьком (англ. Bubble sort) — для каждой пары индексов


производится обмен, если элементы расположены не по порядку.
• Сортировка перемешиванием (англ. Cocktail sort).
• Сортировка вставками (англ. Insertion sort) — определяем, где текущий элемент
должен находиться в упорядоченном списке, и вставляем его туда.
• Гномья сортировка (англ. Gnome sort; первоначально опубликована под
названием «глупая сортировка» [stupid sort] за простоту реализации) — сходна с
сортировкой вставками.
• Сортировка слиянием (англ. Merge sort) — выстраиваем первую и вторую
половину списка отдельно, а затем объединяем упорядоченные списки.
• Сортировка с помощью двоичного дерева (англ. Tree sort).
• Сортировка Timsort (англ. Timsort) — комбинированный алгоритм (используется
сортировка вставками и сортировка слиянием).
Алгоритмы неустойчивой сортировки
• Сортировка выбором (англ. Selection sort) — поиск наименьшего или наибольшего элемента и
помещение его в начало или конец упорядоченного списка.
• Сортировка расчёской (англ. Comb sort)
• Сортировка Шелла (англ. Shell sort) — улучшение сортировки вставками.
• Пирамидальная сортировка (сортировка кучи, Heapsort)
• Плавная сортировка (англ. Smoothsort)
• Быстрая сортировка (англ. Quicksort), широко известен как быстрейший из известных для
упорядочения больших случайных списков; с разбиением исходного набора данных на две половины
так, что любой элемент первой половины упорядочен относительно любого элемента второй
половины; затем алгоритм применяется рекурсивно к каждой половине.
• Интроспективная сортировка (англ. Introsort) сочетание быстрой и пирамидальной сортировки.
• Терпеливая сортировка (англ. Patience sorting) находит самую длинную увеличивающуюся
подпоследовательность.
• Stooge sort — рекурсивный алгоритм сортировки
Непрактичные алгоритмы сортировки

• Bogosort (также глупая сортировка, stupid sort) — Произвольно


перемешать массив, проверить порядок.
• Сортировка перестановкой —Для каждой пары осуществляется
проверка верного порядка и генерируются всевозможные перестановки
исходного массива.
• Бисерная сортировка (англ. Bead sort)
• Блинная сортировка (англ. Pancake sorting)
Алгоритмы, не основанные на сравнениях

• Блочная сортировка (Корзинная сортировка, англ. Bucket sort)


• Поразрядная сортировка (она же цифровая сортировка, англ. Radix
sort)
• Сортировка подсчётом (англ. Counting sort).
Общие принципы объектно-ориентированного программирования

Абстракция
При описании какого-либо объекта, например автомобиля, мы создаём
его модель. Модель не описывает объект полностью – реальные
объекты слишком сложны. Для решения поставленной задачи
отбираются только те характеристики, которые важны для решения
задачи.

Существительные, которые описывают объект – это поля объекта, а


глаголы – методы объекта.
Общие принципы объектно-ориентированного программирования

В ОО языках модель информационного процесса записывается в виде


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

Поля, в которых объект будет хранить необходимую информацию,


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

Методы обработки информации, используемые объектом, описываются


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

Кроме полей и методов в классе можно описать и вложенные классы и


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

Набросок описания смартфона:

class Smartphone {
int capacity; //ёмкость батареи
int screensize;
int onboardMemory;
// и т.д.
void disCharge(int cpuload, boolean screenon) {
int a=0;// cpuload, screenon и a – это локальные переменные, а не поля.
//тело метода – описывается метод вычисления скорости разряда
}
Общие принципы объектно-ориентированного программирования

Далее нужно создавать конкретные объекты, называемые экземплярами


класса. Создание экземпляров класса производится в три этапа, подобно
описанию массива. Сначала объявляются ссылки на объекты –
записываются имя класса и после пробела через запятую перечисляются
экземпляры класса, точнее ссылки на них:

Smartphone htcone, yotaphone2, Samsung;


Общие принципы объектно-ориентированного программирования

Затем операцией new определяются сами объекты, под них выделяется


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

htcone = new Smartphone();


yotaphone2 = new Smartphone();
Samsung = Smartphone();
Общие принципы объектно-ориентированного программирования

На третьем этапе происходит инициализация объектов, задаются начальные


значения. Этот этап, как правило, совмещается со вторым, имен для этого в
операции new повторяется имя класса со скобками Smartphone(): Это так
называемый конструктор класса (о нем чуть позже).

Имена полей, методов и вложенных классов у всех объектов одного класса


одинаково, они заданы в описании класса. Поэтому имена надо уточнять именем
ссылки на объект:
htcone.capasity=2500;
yotaphone2.capasity=2380;
Samsung.capasity=2300;
yotaphone2.disCharge(256,true);
Иерархия

Иногда требуется организовать некое множество классов, разделенное по


некоторым признакам – такое разделение называется иерархией.

Мы можем описать множество мобильных телефонов следующим образом:


class mobphone{
int weight, age, chargeTime;
int charging (int capacity, int chargecurrent, int batterylevel){
//начальные действия
if (batterylevel<10) person.getcharge(capacity, chargecurrent);
}
void option1();
}
Иерархия

Затем создаем классы, описывающие более конкретные объекты, связывая их с


общим классом mobphone:
class Smartphone extends mobphone{ //описываем св-ва, присущие только
смартфонам
int cpuunits; //разрешение экрана
void powerful(); //производительность процессора
// прочие свойства
}

class Classicphone extends mobphone{ //свойства “классических» телефонов


boolean raskladushka;
void calling(); //звонить
Иерархия

Мы не повторяем общие свойства всех мобильных устройств, описанные в классе


mobphone – они наследуются автоматически. Мы можем определить объект класса
Classicphone и использовать в нем все свойства класса mobphone так, будто они
описаны в классе Classicphone. Например, создаем объекты:
Classicphone Motorola=new Classicphone(), LG= new Classicphone();

После этого определения можно будет написать

Motorola.age=5;
int p=LG. charging (2000,2,10);

А классификацию можно продолжить так:


class Nokia extends Classicphone {}
class Panasonic extends Classicphone {}
Иерархия

На каждом последующем уровне иерархии в класс добавляются новые свойства, но


ни одно свойство не пропадает. С другой стороны – кол-во объектов уменьшается –
кол-во Панасоников меньше, чем телефонов.

Можно определить хозяина мобильного устройства:


class Master{
String name;
void getcharge(int capacity, int chargecurrent);
//прочее…
}
Иерархия

package nasled1;

public class Nasled1 {


public static class Mobile extends Nasled1 {
int capacity, phoneBookCapasity; //ёмкость аккумулятора, ёмкость телефонной книги

// базовый метод Звонок


void Ringing() {
System.out.println("General ringing");
}
}
public static class Smartphone extends Mobile {
int screenSize; //размер экрана
String CellGen(){
return "4G";
}
}
Иерархия
public static class ClassicPhone extends Mobile {
int manufYear;
void standbyTime() {
System.out.println("More than 3 days");
}
}

public static class SamsungModel extends Smartphone{


int operMemory;
String onBoardMemory (int gb_mem) {
return "Memory is " + gb_mem + " Gb";
}
}
}
Иерархия
public static void main(String[] args) {

System.out.print("Test1");
//Mobile NewDevice = new Mobile();
//Smartphone Samsung = new Smartphone();
SamsungModel S10 = new SamsungModel();
S10.operMemory = 6;
System.out.println(S10.onBoardMemory(128));
System.out.println("RAM on S10 is " + S10.operMemory);
}
}
Модульность

Каждый класс должен составлять отдельный модуль. Члены класса, к которым не


планируется обращение извне, должны быть инкапсулированы.
В Java инкапсуляция достигается добавлением модификатора private к описанию
члена класса. Например:
private boolean raskladushka;
private String name;

Эти члены классов становятся закрытыми, ими могут пользоваться только


экземпляры того же самого класса.
Модульность

В противоположность закрытости, мы можем объявить некоторые члены класса


Открытыми, записав вместо слова private модификатор public. Например:

public void getcharge(int capacity, int chargecurrent);

к таким членам может обращаться любой объект любого класса.

Принцип модульности предписывает открывать члены класса только в случае


необходимости.
Модульность

Если же надо обратиться к закрытому члену класса, то рекомендуется включить в


класс специальные методы доступа, отдельно для чтения и отдельно для записи.
Имена методов доступа рекомендуется начинать со слов get и set, добавляя к этим
словам имя поля. Для классов Java, используемых как компоненты большого
приложения, эти рекомендации возведены в ранг закона. В нашем примере класса
Master методы доступа к полю name в самом простом случае могут выглядеть так:

public String getName(){


return name;
}
public void setName(String newName){
name=newName;
}
Модульность

Когда надо разрешить доступ наследникам класса, но нежелательно открывать его


всему миру, тогда в Java используется защищенный доступ, отмеченный
модификатором protected, например объект Motorola может обратиться к полю
person родительского класса mobphone, если в классе mobphone это поле описано
так:
protected Master person;
Как описать класс и подкласс?

Описание класса начинается со слова class, после которого с заглавной буквы идет
имя класса.
Перед словом класс можно записать модификаторы класса. Например: public,
abstract, final. Перед именем вложенного класса можно использовать также
модификаторы protected, private, static.
Тело класса, в котором в любом порядке перечисляются поля, методы,
конструкторы, вложенные классы и интерфейсы, заключается в фигурные скобки.
При описании поля указывается его тип, затем, через пробел, имя и может быть
начальное значение после знака равенства, которое допустимо записать
константным выражением.
Как описать класс и подкласс?

public – модификатор доступа. У класса обозначает, что любой класс имеет полный
доступ к членам открытого класса.
abstract – обозначает, что класс является абстрактным – у абстрактного класса
нельзя создать экземпляр класса, а реализовывать этот класс можно только лишь в
классах-потомках. У абстрактного класса не обязательно должны быть абстрактные
методы, но если таковые имеются у какого-либо класса, значит класс обязан быть
абстрактным.
final – обозначает что данный класс нельзя наследовать.
Как описать класс и подкласс?

Описание поля может начинаться с одного или нескольких необязательных


модификаторов public, protected, static, final, transient, volatile. Если надо поставить
несколько модификаторов, то перечислять их необходимо в указанном порядке,
поскольку некоторые компиляторы требуют определенного порядка записи.
static - будет существовать ровно одно значение этого поля, не зависимо от того,
сколько экземпляров класса будет создано, даже если не будет создано ни одного
экземпляра. Такие статические поля еще называют переменными уровня класса
(class variable).
Как описать класс и подкласс?

Поля класса
final - не может поменять своего значения после инициализации. Это касается и
статических, и нестатических полей (member fields).
transient – обозначает, что во время сериализации это поле будет проигнорировано.
volatile - в Java потоки могут хранить значения некоторых переменных в некотором
своем локальном контексте. Если один поток изменит значение такого поля, то
другой поток может об этом не узнать (так как хранит копию). Для полей с
модификатором volatile есть гарантия, что все потоки всегда будут видеть
актуальное значение такой переменной.
При описании метода указывается тип возвращаемого им значения или
слово void, затем, через пробел, имя метода, потом, в скобках, список
параметров. После этого, в фигурных скобках расписывается
выполняемый метод.
Описание метода может начинаться с модификаторов public, protected,
private, abstract, static, final, synchronized, native, strictfp.
В списке параметров через запятую перечисляются тип и имя каждого
параметра. Перед типом какого-либо параметра может стоять
модификатор final. Такой параметр нельзя изменять внутри метода.
Список параметров может отсутствовать, но скобки сохраняются.
abstract - может быть объявлен как метод-член (member method) в
пределах абстрактного класса (или интерфейса). В этом случае тело
метода отсутствует, а реализация может быть предоставлена в классах-
наследниках.
Метод, объявленный с модификатором final не может быть
переопределен в наследниках.
Метод с модификатором static относится к классу в целом, а не к его
экземплярам, то есть в него не передается объект this. Такой метод
может быть вызван используя имя класса.
Модификатор native перед объявлением метода указывает, что он
является специфическим для операционной системы. Как и у
абстрактного метода, у него тоже нет тела, а реализация находится в
скомпилированном виде в файлах JVM.
Модификатор synchronized у метода говорит о том, что перед его
выполнением должен быть захвачен монитор объекта (для
нестатического метода), либо монитор, связанный с классом (для
статического метода)
Передача аргументов в метод

При обращении к методу создаются локальные переменные для


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

При передаче по ссылке в метод поступает не сам аргумент, а его адрес.


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

class Dummy1{
private static void f(int a){
a=5;
}
}
public static void main (String [] args){
int x=7;
System.out.println(“До: “ + x);
f(x);
System.out.println(“После: “ + x);
}

На выходе получим в обоих случаях 7, потому что меняется локальная переменная


а, а не переменная аргумент х.
Передача аргументов в метод

Очень часто у метода встречаются параметры ссылочного типа. В этом


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

class Dummy2{
private static void f (int[] a){
a[0]=5;
}
public static void main(String() args){
int[] x = {7};
System.out.println (“До: “ + x[0]);
f(x);
System.out.println (“После: “ + x[0]);
}
Передача аргументов в метод

переменная х – это ссылка на массив, которая копируется в локальную


переменную, созданную для параметра х. Ссылка а направляется на тот
же массив, что и ссылка х. Она меняет нулевой элемент массива и мы
получаем 7 и 5. По прежнему сделана передача аргумента по значению,
на теперь аргумент – это ссылка и в метод f() передается ссылка, а не
объект, на который она направлена.
Перегрузка методов

Имя метода, число и типы параметров образуют сигнатуру метода.


Компилятор различает методы не по их именам, а по сигнатурам. Это
позволяет записывать разные методы с одинаковыми именами,
различающиеся числом и/или типами параметров.

Тип возвращаемого значения не входит в сигнатуру метода, значит


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

void Multy11 (int a, int b)


{
System.out.println("Result is: " + a*b);
}
String Multy11 (double a, double b)
{
return "" + a*b;
}
public void main(String[] args) {
Multy11 (12, 13);
System.out.println("" + 14.2*155.678);
}
Переопределение методов

Переопределение используется тогда, когда перерабатывается


реализация метода. Переопределение (override) - это способ
поддержания полиморфизма в Java. Переопределение - это наглядный
пример применения принципа полиморфизма.

Не стоит путать переопределение и перегрузку методов. И то и то


позволяет нам создать разные методы с одинаковыми названиями. Но:

переопределение происходит, когда сигнатура у исходного метода и у


"нового" метода одинаковая. То-есть и название, и возвращаемый тип, и
принимаемый тип не меняются.
Переопределение методов
@Override – аннотация – сигнализирует компилятору о необходимости проверить – переопределяем
ли метод.
В Java, когда подкласс содержит метод, переопределяющий метод суперкласса, то он может помимо
своего метода вызывать и метод суперкласса при помощи ключевого слова super [2]. Пример:

public class Thought {


public void message() {
System.out.println("Я себя чувствую как стрекоза, попавшая в параллельную вселенную."); }}

public class Advice extends Thought {


@Override // Аннотация @Override в Java 5 является необязательной, но весьма полезной
public void message() {
System.out.println("Внимание: Даты в календаре ближе, чем кажутся."); }}
Переопределение методов
Класс Thought представляет собой суперкласс и обеспечивает вызов метода message(). Подкласс,
называемый Advice, наследует каждый метод класса Thought. Однако, класс Advice переопределяет
метод message(), замещая функциональность, описанную в классе Thought.

Thought t1 = null;

t1 = new Thought();
t1.message(); // Выводит "Я себя чувствую как стрекоза, попавшая в параллельную вселенную."

t1 = new Advice(); // Полиморфизм


t1.message(); // Выводит "Внимание: Даты в календаре ближе, чем кажутся."
Абстрактные методы и классы

Класс, содержащий абстрактные методы, называется абстрактным


классом. Такие классы помечаются ключевым словом abstract.
Абстрактный метод не завершён. Он состоит только из объявления и не
имеет тела:
abstract void yourMethod();

По сути, создается шаблон метода. Например, можно создать абстрактный метод


для вычисления площади фигуры в абстрактном классе Фигура. А все другие
производные классы от главного класса могут уже реализовать свой код для
готового метода. Ведь площадь у прямоугольника и треугольника вычисляется по
разным алгоритмам и универсального метода не существует.
Абстрактные методы и классы

Если вы объявляете класс, производный от абстрактного класса, но


хотите иметь возможность создания объектов нового типа, вам придётся
предоставить определения для всех абстрактных методов базового
класса. Если этого не сделать, производный класс тоже останется
абстрактным, и компилятор заставит пометить новый класс ключевым
словом abstract.
Можно создавать класс с ключевым словом abstract даже, если в нем не
имеется ни одного абстрактного метода. Это бывает полезным в
ситуациях, где в классе абстрактные методы просто не нужны, но
необходимо запретить создание экземпляров этого класса.
Абстрактные методы и классы

В тоже время абстрактный класс не обязательно должен иметь только


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

Абстрактный класс не может содержать какие-либо объекты, а также


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

Модификатор final может быть использован для переменных, методов,


классов и параметров в методах.
Конструкторы Класса

– это схожая c методом структура, назначение которой состоит в


создании экземпляра класса. Характеристики конструктора:
• Имя конструктора должно совпадать с именем класса (по
договоренности, первая буква — заглавная, обычно имя
существительное);
• Конструктор имеется в любом классе. Даже если вы его не написали,
компилятор Java сам создаст конструктор по умолчанию (default
constructor), который будет пустым и не делает ничего, кроме вызова
конструктора суперкласса.
Конструкторы Класса

• Конструктор похож на метод, но не является методом, он даже не


считается членом класса. Поэтому его нельзя наследовать или
переопределить в подклассе;
• Конструкторы не наследуются;
• Конструкторов может быть несколько в классе. В этом случае
конструкторы называют перегруженными;
• Если в классе не описан конструктор, компилятор автоматически
добавляет в код конструктор без параметров;
Конструкторы Класса

• Конструктор похож на метод, но не является методом, он даже не


считается членом класса. Поэтому его нельзя наследовать или
переопределить в подклассе;
• Конструкторы не наследуются;
• Конструкторов может быть несколько в классе. В этом случае
конструкторы называют перегруженными;
• Если в классе не описан конструктор, компилятор автоматически
добавляет в код конструктор без параметров;
• Конструктор не имеет возвращаемого типа, им не может быть даже
тип void, если возвращается тип void, то это уже не конструктор а
метод, несмотря на совпадение с именем класса.
• В конструкторе допускается оператор return, но только пустой, без
всякого возвращаемого значения;
Конструкторы Класса

• В конструкторе допускается применение модификаторов доступа, можно задать


один из модификаторов: public, protected, private или без модификатора.
• Конструктор не может иметь модификаторов abstract, final, native, static или
synchronized;
• Ключевое слово this cсылается на другой конструктор в этом же классе. Если
используется, то обращение должно к нему быть первой строкой конструктора;
• Ключевое слово super вызывает конструктор родительского класса. Если
используется, должно обращение к нему быть первой строкой конструктора;
• Если конструктор не делает вызов конструктора super класса-предка (с
аргументами или без аргументов), компилятор автоматически добавляет код вызова
конструктора класса-предка без аргументов;
Конструктор по умолчанию

Конструктор имеется в любом классе. Даже если вы его не написали, компилятор


Java сам создаст конструктор по умолчанию (default constructor). Этот конструктор
пустой и не делает ничего, кроме вызова конструктора суперкласса. Т.е. если
написать:
public class Example {}
то это эквивалентно написанию:
public class Example
{
Example()
{
super;
}
}
Конструктор по умолчанию

В данном случае явно класса предка не указано, а по умолчанию все классы Java
наследуют класс Object поэтому вызывается конструктор класса Object. Если в
классе определен конструктор с параметрами, а перегруженного конструктора без
параметров нет, то вызов конструктора без параметров является ошибкой. Тем не
менее, в Java, начиная с версии 1.5, можно использовать конструкторы с
аргументами переменной длины. И если есть конструктор, имеющий аргумент
переменной длины, то вызов конструктора по умолчанию ошибкой не будет. Не
будет потому, что аргумент переменной длины может быть пустым.
Создание объекта и конструкторы
При создании объекта последовательно выполняются следующие действия:
• Ищется класс объекта среди уже используемых в программе классов. Если его
нет, то он ищется во всех доступных программе каталогах и библиотеках. После
обнаружения класса в каталоге или библиотеке выполняется создание, и
инициализация статических полей класса. Т.е. для каждого класса статические поля
инициализируются только один раз.
• Выделяется память под объект.
• Выполняется инициализация полей класса.
• Отрабатывает конструктор класса.
• Формируется ссылка на созданный и инициализированный объект. Эта ссылка и
является значением выражения, создающего объект. Объект может быть создан и с
помощью вызова метода newInstance() класса java.lang.Class. В этом случае
используется конструктор без списка параметров.
Перегрузка конструкторов

Конструкторы одного класса могут иметь одинаковое имя и различную


сигнатуру. Такое свойство называется совмещением или
перегрузкой(overloading). Если класс имеет несколько конструкторов, то
присутствует перегрузка конструкторов.
Перегрузка конструкторов

public class Car1


{
int carCountWheel, weightOfTheCar;
Car1 (int wheels, int weight)
{
carCountWheel = wheels;
weightOfTheCar = weight;
}
}
Статические члены класса

Разные экземпляры одного класса имеют совершенно независимые друг


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

Class Mobile{
Private static int number;
Mobile(){
number++;
System.out.println(“Show mobile imei ” + number);
}

Public class MobileTest{


Public static void main (String[] args){
Mobile Moto=new Mobile(),
Nokia=new Mobile()…
Статические члены класса

К статическим полям можно обращаться с именем класса


Mobile.number, а не только с именем экземпляра, Moto.number, причем
это можно делать, даже если не создан ни одни экземпляр класса. Дело
в том, что поля класса определяются при загрузке файла с классом в
оперативную память, еще до создания экземпляров класса.

Для работы с такими статическими полями обычно создаются


статические методы, помеченные модификатором static. Для методов
слово static имеет совсем другой смысл, чем для полей, потому что
исполняющая система Java всегда создает в памяти только одну копию
машинного кода метода, разделяемую всеми экземплярами, независимо
от того, статический это метод или нет.
Статические члены класса

Основная особенность статических методов – они работают напрямую


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

Поэтому статические методы называются методами класса, в отличие от


нестатических методов, называемых методами экземпляра.
Отсюда вытекают другие особенности статических методов:
1. В статическом методе нельзя использовать ссылки this и super.
2. Статические методы не могут быть абстрактными.
3. Статические методы переопределяются в подклассах только как
статические.
4. При переопределении статических методов полиморфизм не
действует, ссылки всегда направляются на методы класса, а не объекта.
Статические члены класса

Статические переменные инициализируются еще до начала работы


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

Всякая программа, оформленная как приложение, должна содержать


метод с именем main. Он может быть один на всё приложение или
присутствовать в некоторых класса этого приложения, а может
находится и в каждом классе.

Метод main() записывается как обычный метод, может содержать


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

В языке Java нестатические переменные разрешено объявлять в любом месте кода


между операторами. Статические переменные могут быть только полями класса, а
значит, не должны объявляться внутри методов и блоков.

Существует так называемый блок инициализации экземпляра – просто блок


операторов в фигурных скобках, но записывается он вне всякого метода, прямо в
теле класса. Этот блок выполняется при создании каждого экземпляра, после static-
блоков и инициализации при объявлении переменных, но до выполнения
конструктора. Он играет такую же роль, как и static-блок для статичных
переменных. Он применяется в тех случаях, когда конструктор написать нельзя, а
именно в безымянных внутренних классах.
Вложенные классы

Все вложенные классы можно разделить на вложенные классы-члены


класса, описанные вне методов, и вложенные локальные классы,
описанные внутри методов и/или блоков. Локальные классы, как и все
локальные переменные, не являются членами класса.
Классы-члены могут быть объявлены статически с помощью
модификатора static. Поведение статических классов-членов ничем не
отличается от поведения обычных классов, отличается только
обращение к таким классам. Поэтому они называются вложенным
классами верхнего уровня, хотя статические классы-члены можно
вкладывать друг в друга. В них можно объявить статические члены.
Используются они обычно для того, чтобы сгруппировать
вспомогательные классы вместе с основным классом.
Вложенные классы

Все нестатические вложенные классы называются внутренними. В них


нельзя объявлять статические члены.
Локальные классы, как и все локальные переменные, известны только в
блоке, в котором они определены. Они могут быть безымянными.
1. Доступ к полям внешнего класса возможен отовсюду, даже к
закрытым полям исходного класса. Именно для этого в Java и введены
вложенные классы. Остальные конструкции добавлены вынуждено.
2. Язык Java позволяет использовать одни и те же имена в разных
областях видимости – поэтому пришлось уточнить константу this
именем класса.
Вложенные классы

3. В безымянном классе не может быть конструктора, ведь имя


конструктора должно совпадать с именем класса, - поэтому пришлось
использовать имя суперкласса. Вместо конструктора в безымянном
классе используется блок инициализации экземпляра.
4. Нельзя создать экземпляр вложенного класса, не создав
предварительно экземпляр внешнего класса.
5. При определении экземпляра указывается полное имя вложенного
класса, но в операции new записывается просто конструктор класса.
Вложенные классы

Компилятор разложит «матрешки» и, как всегда, создаст отдельные файлы для


каждого класса. При этом, поскольку в идентификаторах недопустимо использовать
точки, компилятор заменит их на знаки доллара. Для безымянного класса
компилятор придумает имя. Локальный класс компилятор пометит номером.
Вложенные классы существуют только на уровне исходного кода. Виртуальная
машина Java ничего не знает о вложенных классах. Она работает с обычными
внешними классами. Для взаимодействия объектов вложенных классов компилятор
вставляет в них специальные закрытые поля. Поэтому в локальных классах можно
использовать только константы объемлющего метода, т.е. переменные, помеченные
словом final. Виртуальная машина просто не догадается передавать изменяющиеся
значения переменных в локальный класс. Таким образом, не имеет смысла помечать
вложенные классы модификатором private, все равно они выходят на самый
внешний уровень.
Вложенные классы

Вложенные классы в Java используются, как правило, только в самом простом виде,
главным образом для обработки событий, возникающих при действиях с мышью и
клавиатурой.
Вложение класса удобно тем, что методы внешнего класса могут напрямую
обращаться к полям и методам вложенного класса. Но ведь того же самого можно
было бы добиться по-другому – при помощи наследования.
Отношения «быть частью» и «являться»

Существует две различные иерархии классов. Одну иерархию образует


наследование классов, другую – вложенность классов.

Теория ООП советует прежде всего выяснить, в каком отношении


находятся объекты классов. Например, мобильный телефон является
мобильным устройством или частью мобильного устройства?
Процессор является мобильным устройством или частью мобильного
устройства? В первом случае лучше использовать наследование, а во
втором – вложенные классы.
Отношения «быть частью» и «являться»

Отношение «класс А является экземпляром класса В» по-английски


записывается как «А class is a class B», поэтому в теории ООП
называется отношение «is-a». Отношение же «класс А является частью
класса В» по-английски «A class has a class B», и такое отношение
называется отношением «has-a».

Отношение «is-a» - это отношение «обобщение-детализация»,


отношение большей и меньшей абстракции, и ему соответствует
наследование классов.
Отношение «has-a» - это отношение «целое-часть» и ему соответствует
вложение классов.
Вложенные и внутренние классы

Определение класса может размещаться внутри определения другого


класса. Такие классы называются вложенными или внутренними.

Область видимости вложенного класса ограничена областью видимости


внешнего класса. Поэтому, если вы создадите класс B внутри класса A,
то класс B не сможет существовать независимо от класса A.
Вложенные классы позволяют группировать классы, логически
принадлежащие друг другу, и управлять доступом к ним.
Существуют два типа вложенных классов - статические и
нестатические.
Вложенные классы

Если связь между объектом внутреннего класса и объектом внешнего


класса не нужна, можно сделать внутренний класс статическим (static).
Такой класс называют вложенным (nested).

Применение статического внутреннего класса означает следующее:


• для создания объекта статического внутреннего класса не нужен
объект внешнего класса;
• из объекта вложенного класса нельзя обращаться к нестатическим
членам внешнего класса;
Вложенные классы

Вложенный класс имеет доступ к членам своего внешнего класса, в том


числе и к закрытым членам. Однако, внешний класс не имеет доступа к
членам вложенного класса. Вложенный класс при этом является членом
внешнего класса.
Статический класс объявляется ключевым словом static. При этом класс
должен обращаться к нестатическим членам своего внешнего класса
при помощи объекта, т.е. он не может обращаться напрямую на
нестатические члены своего внешнего класса. На практике подобные
классы используются редко.
Вложенные классы

Внутренние классы

Нестатические вложенные классы называют также внутренними


классами (inner). Внутренний класс имеет доступ ко всем переменным и
методам своего внешнего класса и может непосредственно ссылаться на
них.
Внутренние классы создаются внутри окружающего класса.
Вложенные классы

public class Test1 {


String perem1="Perem1", perem2;
String Met1(){return perem2=perem1+"+"+"dobav";}
String ToOver(){return "Super";}
class inner{
String peremIn1="PeremIn1", peremIn2;
String MetIn2(){return peremIn2=peremIn1+"+"+"dobavIn";}
String ToOver(){
return "Inner"; } }

public static void main(String[] args) {


Test1 TestOut=new Test1();
Test1.inner TestIn=TestOut.new inner();
System.out.println(TestOut.perem1+" "+TestOut.Met1()+" "+TestIn.peremIn1+" "+TestIn.MetIn2());
System.out.println(TestIn.ToOver());
System.out.println(TestOut.ToOver()); }
Вложенные классы

public class Test1 {


String perem1="Perem1", perem2;
String Met1(){return perem2=perem1+"+"+"dobav";}
String ToOver(){return "Super";}
static class Inner{
String peremIn1="PeremIn1", peremIn2;
String MetIn2(){return peremIn2=peremIn1+"+"+"dobavIn";}
String ToOver(){
return "Inner";} }

public static void main(String[] args) {


//Test1 TestOut=new Test1();
Inner TestIn=new Inner();
System.out.println(/*TestOut.perem1+" "+TestOut.Met1()+" "+*/TestIn.peremIn1+"
"+TestIn.MetIn2());
System.out.println(TestIn.ToOver());
//System.out.println(TestOut.ToOver());}
Пакеты, интерфейсы, перечисления

Библиотеки классов, кроме стандартной библиотеки, не являются


частью языка.
Разработчики Java включили в язык дополнительную конструкцию –
пакеты. Все классы Java распределяются по пакетам. Кроме классов
пакеты могут содержать интерфейсы и вложенные подпакеты.
Образуется древовидная структура пакетов и подпакетов.
Эта структура в точности отображается на структуру файловой
системы. Все файлы с расширением class, образующие один пакет,
хранятся в одном каталоге файловой системы. Подпакеты образуют
подкаталоги этого каталога.
Пакеты, интерфейсы, перечисления

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

Пакетами пользуются для того, чтобы добавить к уже имеющимся


правам доступа к членам класса private, protected и public еще один –
«пакетный» уровень доступа.
Если член класса не отмечен ни одним из модификаторов private,
protected или public, то по умолчанию к нему осуществляется пакетный
доступ, т.е. к такому члену может обратиться любой метод класса из
того же пакета. Пакеты ограничивают доступ к классу целиком – если
класс не помечен модификатором public, его члены, даже открытые, не
будут видны из других пактов.
Члены пакетного доступа не видны в подпакетах данного пакета.
Пакет и подпакет
 
Чтобы создать пакет, надо в первой строчке java-файла c исходным кодом написать
строку.
Package имя; (например package mypack;)
Тем самым создается пакет с указанным именем майпэк и все классы, записанные в
этом файле, попадут в пакет майпэк. Повторяя эту строку в начале каждого
исходного файла, включаемв пакет новый файлы.
Имя подпакета уточняется именем пакета. Чтобы создать подпакет с именем,
например, сабпакет, следует в первой строке исходного файла написать:
Package mypack.subpack;
И все классы этого файла и всех файлов с такой же первой строкой попадут в
подпакет сабпак пакета майпэк.
Пакет и подпакет
 
Можно создать и подпакет подпакета, написав майпэк.сабпэк.саб и т.д.
Поскольку строка packge имя только одна и это обязательно первая строка файла,
каждый класс попадает только в один пакет или подпакет. Компилятор Java может
сам создать каталог с тем же именем mypack, а в нем подкаталог subpack и
разместить в них class-файлы с байт-кодами.
Полные имена классов А и В будуь выглядеть так: mypack.A, mypack.B.
Соглашение рекомендует записывать имена пакетов строчными буквами. Тогда они
не будут совпадать с именами классов, которые, по соглашению, начинаются с
прописной буквы. Кроме того, соглашение советует использовать в качестве имени
пакета или подпакета доменное имя своего сайта, записанное в обратном порядке.
Com.sun.developer.
Пакет и подпакет
 
Куда же попадают наши файлы с откомпилированными классами?
Компилятор всегда создает для таких классов безымянный пакет, которому
соответствует текущий каталог файловой системы. Вот поэтому у нас class-файл
всегда оказывался в том же каталоге, что и соответствующий исходный java-файл.
Безымянный пакет служит обычно хранилищем небольших пробных или
промежуточных классов. Большие проекты лучше хранить в пакетах. Более того,
некоторые программные продукты Java вообще не работают с безымянными
пакетами. Поэтому в технологии Java рекомендуется все классы помещать в пакеты.
Права доступа к членам класса

Из независимого класса можно обратиться только к открытым (public),


полям класса другого пакета. Из подкласса можно обратиться еще и к
защищенным (protected), полям, но только унаследованным
непосредственно, а не через экземпляр суперкласса. Все указанное
относится не только к полям, но и к методам.
  Класс Пакет Пакеты и Все классы
подпакеты

private +      
“packadge” + +    

protected + + *  
public + + + +
Импорт классов и пакетов

Компилятор будет искать классы только в двух пакетах: в том, что


указан в первой строке файла, и в пакете стандартных классов java.lang.
Для классов из другого пакета надо указывать полные имена.
Правила использования оператора import: пишется слово import и через
пробел – полное имя класса, завершенное точной с запятой. Сколько
классов, столько и операторов import.
Можно также написать import p1.*; этой записью компилятору
предписываетя просмотреть весь пакет. Импортировать разрешается
только открытые классы, помеченные модификатором public.
Импорт классов и пакетов

Пакет java.lang просматривается всегда, его необязательно импортировать.


Остальные пакеты стандартной библиотеки надо указывать в операторах import,
либо записывать полные имена классов.
Существует еще одна форма оператора import, предназанченная для поиска
статических полей и методов класса – оператор import static.
import static java.lang.Math.*;
После этого все статические поля и методы класса Math можно использовать без
указания имени класса. Вместо записи
double r=Math.cos(Math.PI*alpha);
можно записать просто
double r=cos(PI*alpha);

Оператор import не означает никаких перемещений классов.


Интерфейсы

Сделать расширение можно только от одного класса. Все классы


происходят только от класса Object. Часто возникает необходимость
породить класс от двух классов. Это называется множественным
наследованием. Но если родительские классы сами порождены от
одного предка, возникают трудности (ромбовидное наследование).

В Java запрещено множественное наследование вообще. При


расширении класса после слова extends можно написать только одно
имя суперкласса. С помощью уточнения super можно обратиться только
к членам непосредственного суперкласса.
Интерфейсы

Как действовать, если необходимо использоваться несколько предков?


Например, есть общий класс автомобилей Auto, от которого можно
породить класс грузовиков Truck и класс легковых авто Car.
Необходимо описать класс Pickup, который должен наследовать
свойства грузовых и легковых авто.
Для этого существует еще одна конструкция Java – интерфейсы,
которые в отличии от классов, содержат только константы и заголовки
методов, без их реализации.
Интерфейсы тоже размещаются в пакетах и подпакетах, часто в тех же
самых, что и классы, и тоже компилируются в класс-файлы.
Интерфейсы

Описание интерфейса начинается со слова interface, перед которым


может стоять модификатор public, означающий, как и для классов, что
интерфейс доступен всюду. Если же модификатора public нет,
интерфейс будет виден только в своем пакете.
После слова interface записывается имя интерфейса, потом может стоять
слово extends и список интерфейсов-предков через запятую. Таким
образом, одни интерфейсы могут порождаться от других интерфейсов,
образую свою, независимую от классов, иерархию, причем в ней
допускается множественное наследование интерфейсов. В этой
иерархии нет корня, общего предка.
Интерфейсы

Затем в фигурных скобках записывается в любом порядке константы и


заголовки методов. Можно сказать, что в интерфейсе все методы
абстрактные, но слово abstract писать не надо. Константы всегда
статические, но слова static и final указывать не надо. Все эти
модификаторы принимаются по умолчанию.
Все константы и методы в интерфейсах всегда открыты, не обязательно
даже указывать модификатор public.
Иерархия автомобилей:
interface Auto { . . .}
interface Car extends Auto{ . . .}
interface Truck extends Auto{ . . .}
interface Pickup extends Car, Truck{ . . }
Интерфейсы

Интерфейс – это набросок, эскиз. В нем указано, что делать, но не указано,


как это сделать.
Используется не интерфейс, а его реализацию. Реализация интерфейса –
это класс, в котором расписываются методы одного или нескольких
интерфейсов. В заголовке класса после его имени или после имени его
суперкласса, если он есть, записывается слово implements и, через запятую,
перечисляются имена интерфейсов.
Примеры реализации:
interface Auto{ . . .}
interface Car extends Auto { . . . }
class Truck implements Auto{ . . .}
class Pickup extends Truck implements Car { . . . }
Интерфейсы

или
interface Auto{ . . .}
interface Car extends Auto { . . . }
class Truck implements Auto{ . . .}
class Pickup implements Truck, Car { . . . }

Реализация интерфейса может быть неполной, некоторые методы


интерфейса могут быть расписаны, а другие – нет. Такая реализация –
абстрактный класс, его обязательно надо пометить модификатором abstract.
Интерфейсы

При этом в классе Pickup невозможно реализовать метод f(), описанный и в интерфейсе
Car, и в интерфейсе Truck с одинаковой сигнатурой.
Интерфейсы позволяют реализовывать средствами Java чистое объектно-
ориентированное проектирование, не отвлекаясь на вопросы реализации проекта.
Приступая к разработке проекта можно записать его в виде иерархии интерфейсов, не
думая о реализации, а затем построить по этому проекту иерархию классов, учитывая
ограничения одиночного наследования и видимости членов классов.
Возможно создавать ссылки на интерфейсы. Конечно, указывать такая ссылка может
только на какую-нибудь реализацию интерфейса. Тем самым мы получаем еще один
способ организации полиморфизма.
Интерфейсы

При этом в классе Pickup невозможно реализовать метод f(), описанный и в интерфейсе
Car, и в интерфейсе Truck с одинаковой сигнатурой.
Интерфейсы позволяют реализовывать средствами Java чистое объектно-
ориентированное проектирование, не отвлекаясь на вопросы реализации проекта.
Приступая к разработке проекта можно записать его в виде иерархии интерфейсов, не
думая о реализации, а затем построить по этому проекту иерархию классов, учитывая
ограничения одиночного наследования и видимости членов классов.
Возможно создавать ссылки на интерфейсы. Конечно, указывать такая ссылка может
только на какую-нибудь реализацию интерфейса. Тем самым мы получаем еще один
способ организации полиморфизма.
Интерфейсы

Нет однозначного ответа – что лучше использовать: абстрактный класс или


интерфейс? На этот вопрос нет однозначного ответа.
Создавая абстрактный класс, волей-неволей погружаем его в иерархию
классов, связанную условиями одиночного наследования и единым
предком – классом Odject. Пользуясь интерфейсами, вы можете свободно
проектировать систему, не задумывасяь об этих ограничения.
С другой стороны, в абстрактных классах можно сразу реализовывать
часть методов. Реализуя же интерфейсы, мы обречены на переопределение
всех методов.
Интерфейсы

Нет однозначного ответа – что лучше использовать: абстрактный класс или


интерфейс? На этот вопрос нет однозначного ответа.
Создавая абстрактный класс, волей-неволей погружаем его в иерархию
классов, связанную условиями одиночного наследования и единым
предком – классом Odject. Пользуясь интерфейсами, вы можете свободно
проектировать систему, не задумывасяь об этих ограничения.
С другой стороны, в абстрактных классах можно сразу реализовывать
часть методов. Реализуя же интерфейсы, мы обречены на переопределение
всех методов.
Перечисления

Начиная с версии Java SE5 для записи констант были введены


перечисления. Создавая перечисление, мы сразу указываем константы,
входящие в него.

enum Lights {RED, YELLOW, GREEN, ERROR}


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

public enum DayOfWeek { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY,


FRIDAY, SATURDAY }

Создание переменной типа перечисление (методе main):


private DayOfWeek dayOfWeek;
Перечисления

public enum DayOfWeek { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,


SATURDAY }

public void takeLunch(DayOfWeek dayOfWeek) {


switch (dayOfWeek) {
case SUNDAY:
System.out.println(“Воскресный обед");
case MONDAY:
System.out.println(«Понедельношный обед");
case TUESDAY:
System.out.println(" Вторнишный обед");
//...и так далее до конца
}
}
Перечисления

По сравнению с обычными классами, на Enum наложили одно серьезное ограничение


— от него невозможно наследоваться.

Кроме того, у перечислений есть характерные только для них методы:


values(): возвращает массив из всех хранящихся в Enum значений:
public static void main(String[] args) {
System.out.println(Arrays.toString(DayOfWeek.values()));
}
Вывод:
[DayOfWeek{title='Воскресенье'}, DayOfWeek{title='Понедельник'},
DayOfWeek{title='Вторник'}, DayOfWeek{title='Среда'}, DayOfWeek{title='Четверг'},
DayOfWeek{title='Пятница'}, DayOfWeek{title='Суббота'}]
Перечисления

ordinal(): возвращает порядковый номер константы. Отсчет начинается с нуля:


public static void main(String[] args) {
int sundayIndex = DayOfWeek.SUNDAY.ordinal();
System.out.println(sundayIndex);
}
Вывод: 0

valueOf(): возвращает объект Enum, соответствующий переданному имени:


public static void main(String[] args) {
DayOfWeek sunday = DayOfWeek.valueOf("SUNDAY");
System.out.println(sunday);
}
Вывод:
DayOfWeek{title='Воскресенье'}
Перечисления

Константы, входящие в перечисление, рассматриваются как константные


вложенные классы. Поэтому в них можно определять константно-
зависимые поля и методы. Одно такое закрытое поле есть в каждой
константе любого перечисления. Оно хранит порядковый номер
константы, возвращаемый методом ordinar().
Можно добавлять в каждую константу свои поля и методы.
Классы-оболочки и generics

В JAVA все что можно представлено объектами. Восемь примитивных типов нарушают
это правило. Арифметические действия удобнее и быстрее производить с обычными
числами, а не с объектами классов, которые требуют много ресурсов.

Для примитивных типов данных в Java созданы соответствующие классы-оболочки.


Главное их предназначение – действия типичные при работе с классами – создание
объектов, преобразование типов объектов, получение численных значений объектов в
разных формах и передачи в методы по ссылке.
Классы-оболочки и generics
Иерархия классов примитивных типов

Object Number BigDemical


BigInteger
Boolean Byte
Double
Character Float
Integer
Class Long
Short

Character.Subset InputSubset
Character.UnicodeBlock
Числовые классы

В каждом из шести числовых классов-оболочек есть статические методы


преобразования строки символов типа String, представляющей число, в
соответствующий примитивный тип:
Byte.parseByte(), Double.parseDouble(), Float.parseFloat(), Integer.parseInt(),
Long.parseLong(), Short.parseShort(). Исходная строка типа String, как всегда в
статических методах, служит параметром метода. Эти методы полезны при вводе
данных в поля ввода, обработке аргументов командной строки, т.е. всюду, где числа
представляются строками символов, состоящими из цифр со знаками плюс или минус и
десятичной точкой.
В каждом их этих классов есть статические константы MAX_VALUE и MIN_VALUE,
показывающие диапазон числовых значений соответствующих примитивных типов.
Автоматическая упаковка и распаковка типов

Создание объекта числового класса:


Integer k1 = Integer.valueOf(55);
эквивалентно
Integer k1 = 55; //автоматическая упаковка числового значения в объект.

Автоматическая распаковка:
int n = k1; //компилятор извлечет из объекта k1 числовое значение 55 методом
intValue().

Не стоит писать конструкции типа k1+k2/k1.


Настраиваемые типы (generics)

Настраиваемые типы – конструкции, позволяющие создавать шаблоны классов,


интерфейсов и методов, в котором есть поле неопределенного пока типа.

public class NastTipy<Ttype> {


private Ttype data;
public NastTipy(){}
public NastTipy (Ttype data){
this.data = data;}
public Ttype getData() {
return data;}
public void setData(Ttype data) {
this.data = data;}
}
Настраиваемые типы (generics)

Перед использованием класса-шаблона его необходимо настроить, задав при


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

public static void main(String[] args) {

NastTipy<Integer> objNastTypINT = new NastTipy<Integer>(55);


Integer n = objNastTypINT.getData();

NastTipy<Double> objNastTypDOU = new NastTipy<Double>(1.2233);


Double dd = objNastTypDOU.getData();
}
Настраиваемые типы (generics)

У настраиваемого типа может быть более одного параметра. Они перечисляются в


угловых скобках через запятую.

public class NastTipy<Ttype, Stype> {


private Ttype data;
private Stype id;
public NastTipy(){}
public NastTipy (Stype id, Ttype data){
this.id = id;
this.data = data;}
…..
Настраиваемые типы (generics)

Неопределенные типы могут быть параметрами конструкторов, типами возвращаемых


значений, параметрами методов, а также типами параметров и типами возвращаемых
значений.

Абстрактный пример:
public NastTipy<Stype, Ttype> makeClass (Stype id, NastTipy2<Ttype> data){
return new NastTipy(id, data.getData());
}
Шаблоны типа (wildcard type)

В Java можно определить ссылку типа суперкласса, ссылающуюся на объект подкласса,


например:
Number nL = new Long(12345L);
Number nD = new Double (27.3355);
Number [] nLMass = new Long[100];

Шаблон типа обозначается вопросительным знаком, например:


public NastTipy<? extends Number, ? extends Number> n = NNN.makeClass(12345L,
objNastTypDOU);

При определении массива (только определении массива):


Average<? Extends Number>[] a = new Average<?>[10];
Настраиваемые методы

Параметры настраиваемого метода указываются в заголовке метода в угловых скобках


перед типом возвращаемого значений:

public class TuneMethods {


public <Par1, Par2> Method11<Par1, Par2> mskeMeth (Par1 id, NewMethhh<T> data){
return new Method11 (id, data.getData());
}
}

Специально настраивать метод не нужно, конкретные типы его параметров и


возвращаемого значения определяются компилятором по переданным в метод
аргументам.
Потоки

Наиболее очевидная область применения многопоточности – это программирование


интерфейсов. Многопоточность незаменима тогда, когда необходимо, чтобы
графический интерфейс продолжал отзываться на действия пользователя во время
выполнения некоторой обработки информации. Например, поток, отвечающий за
интерфейс, может ждать завершения другого потока, загружающего файл из интернета,
и в это время выводить некоторую анимацию или обновлять прогресс-бар. Кроме того,
он может остановить поток загружающий файл, если была нажата кнопка «отмена».
Еще одна популярная и, пожалуй, одна из самых хардкорных областей применения
многопоточности – игры. В играх различные потоки могут отвечать за работу с сетью,
анимацию, расчет физики и т.п.
Процессы

Процесс — это совокупность кода и данных, разделяющих общее


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

Для каждого процесса ОС создает так называемое «виртуальное адресное


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

При запуске программы операционная система создает процесс, загружая в


его адресное пространство код и данные программы, а затем запускает
главный поток созданного процесса.
Потоки

Один поток – это одна единица исполнения кода. Каждый поток


последовательно выполняет инструкции процесса, которому он
принадлежит, параллельно с другими потоками этого процесса.

Следует отдельно обговорить фразу «параллельно с другими потоками».


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

Один поток – это одна единица исполнения кода. Каждый поток


последовательно выполняет инструкции процесса, которому он
принадлежит, параллельно с другими потоками этого процесса.

Следует отдельно обговорить фразу «параллельно с другими потоками».


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

Однако запуск нескольких параллельных потоков возможен и в системах с


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

Проще говоря, при псевдопараллельном выполнении потоков процессор


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

Инструкции процессора (зеленые – инструкции главного потока, синие –


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

То, что инструкции параллельных потоков выполняются вперемешку, в


некоторых случаях может привести к конфликтам доступа к данным.
Запуск потоков

Каждый процесс имеет хотя бы один выполняющийся поток. Тот поток, с


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

В языке Java поток представляется в виде объекта-потомка класса Thread.


Этот класс инкапсулирует стандартные механизмы работы с потоком.

Запустить новый поток можно двумя способами.


Запуск потоков

Способ 1
Создать объект класса Thread, передав ему в конструкторе нечто, реализующее
интерфейс Runnable. Этот интерфейс содержит метод run(), который будет выполняться
в новом потоке. Поток закончит выполнение, когда завершится его метод run().

class TestThread implements Runnable {


public void run(){ System.out.println("Побочный поток!");}
}
public class Program {
static TestThread mThing:
public static void main(String[] args) {
mThing = new TestThread ();
Thread myThready = new Thread(mThing);
myThready.start();
System.out.println("Главный поток завершён..."); } }
Запуск потоков

Способ 2
Создать потомка класса Thread и переопределить его метод run():

class AffableThread extends Thread {


@Override
public void run(){
System.out.println("Привет из побочного потока!"); } }
public class Program {
static AffableThread mSecondThread;
public static void main(String[] args) {
mSecondThread = new AffableThread();
mSecondThread.start();
System.out.println("Главный поток завершён..."); } }
Управление потоками

Важно отметить, что после вызова метода mSecondThread.start() главный поток


продолжает своё выполнение, не дожидаясь пока порожденный им поток завершится. И
те инструкции, которые идут после вызова метода start(), будут выполнены параллельно
с инструкциями потока mSecondThread.

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


главным потоком (main). От него порождаются дочерние потоки. Главный поток, как
правило, является последним потоком, завершающим выполнение программы.
Несмотря на то, что главный поток создаётся автоматически, им можно управлять через
объект класса Thread. Для этого нужно вызвать метод currentThread(), после чего можно
управлять потоком.
Управление потоками

Класс Thread содержит несколько методов для управления потоками.


• getName() - получить имя потока
• getPriority() - получить приоритет потока
• isAlive() - определить, выполняется ли поток
• join() - ожидать завершение потока
• run() - запуск потока. В нём пишите свой код
• sleep() - приостановить поток на заданное время
• start() - запустить поток
• setName() – задать потоку имя
Управление потоками

Thread mainThread = Thread.currentThread();


mInfoTextView.setText("Текущий поток: " + mainThread);
В этом случае можно увидеть строчку Текущий поток: [main,5,main] - имя потока, его
приоритет и имя его группы.
Главный поток завершает работу раньше, чем порожденный им дочерний поток.
Можно создавать несколько потоков:
public static void main(String[] args) {

System.out.println("Main thread started...");


for(int i=1; i < 6; i++)
new JThread("JThread " + i).start();
System.out.println("Main thread finished...");
}
Управление потоками

Как правило, более распространенной ситуацией является случай, когда Main thread
завершается самым последним. Для этого надо применить метод join()
имя_потока.join().

public static void main(String[] args) {


System.out.println("Main thread started...");
JThread t= new JThread("JThread ");
t.start();
try{
t.join();}
catch(InterruptedException e){
System.out.printf("%s has been interrupted", t.getName());}
System.out.println("Main thread finished...");}
Управление потоками

Как правило, более распространенной ситуацией является случай, когда Main thread
завершается самым последним. Для этого надо применить метод join()
имя_потока.join().
public static void main(String[] args) {
System.out.println("Main thread started...");
JThread t= new JThread("JThread ");
t.start();
try{
t.join();}
catch(InterruptedException e){
System.out.printf("%s has been interrupted", t.getName());}
System.out.println("Main thread finished...");}
Метод join() заставляет вызвавший поток (в данном случае Main thread) ожидать
завершения вызываемого потока, для которого и применяется метод join (в данном
случае JThread).
Завершение процесса и демоны

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

Однако это правило не относится к особому виду потоков – демонам. Если завершился
последний обычный поток процесса, и остались только потоки-демоны, то они будут
принудительно завершены и выполнение процесса закончится. Чаще всего потоки-
демоны используются для выполнения фоновых задач, обслуживающих процесс в
течение его жизни.

Объявить поток демоном достаточно просто — нужно перед запуском потока вызвать
его метод setDaemon(true);
Проверить, является ли поток демоном, можно вызвав его метод boolean isDaemon();
Метод Thread.sleep()

Thread.sleep() — статический метод класса Thread, который


приостанавливает выполнение потока, в котором он был вызван. Во время
выполнения метода sleep() система перестает выделять потоку
процессорное время, распределяя его между другими потоками. Метод
sleep() может выполняться либо заданное кол-во времени (миллисекунды
или наносекунды) либо до тех пор пока он не будет остановлен
прерыванием (в этом случае он сгенерирует исключение
InterruptedException).

Thread.sleep(1500); //Ждет полторы секунды


Thread.sleep(2000, 100); //Ждет 2 секунды и 100 наносекунд
Метод yield()

Статический метод Thread.yield() заставляет процессор переключиться на


обработку других потоков системы. Метод может быть полезным,
например, когда поток ожидает наступления какого-либо события и
необходимо чтобы проверка его наступления происходила как можно чаще.
В этом случае можно поместить проверку события и метод Thread.yield() в
цикл:

while(!msgQueue.hasMessages()) //Пока в очереди нет сообщений


{
Thread.yield(); //Передать управление другим потокам
}
Метод join()

В Java предусмотрен механизм, позволяющий одному потоку ждать


завершения выполнения другого. Для этого используется метод join().
Например, чтобы главный поток подождал завершения побочного потока
myThready, необходимо выполнить инструкцию myThready.join() в главном
потоке. Как только поток myThready завершится, метод join() вернет
управление, и главный поток сможет продолжить выполнение.
Метод join() имеет перегруженную версию, которая получает в качестве
параметра время ожидания. В этом случае join() возвращает управление
либо когда завершится ожидаемый поток, либо когда закончится время
ожидания. Подобно методу Thread.sleep() метод join может ждать в течение
миллисекунд и наносекунд – аргументы те же.
Метод join()

С помощью задания времени ожидания потока можно, например,


выполнять обновление анимированной картинки пока главный (или любой
другой) поток ждёт завершения побочного потока, выполняющего
ресурсоёмкие операции:
Thinker brain = new Thinker();
brain.start();
do
{ mThinkIndicator.refresh();
try{
brain.join(250);
}catch(InterruptedException e){}}
while(brain.isAlive());
Приоритеты потоков

Каждый поток в системе имеет свой приоритет. Приоритет – это некоторое


число в объекте потока, более высокое значение которого означает
больший приоритет. Система в первую очередь выполняет потоки с
большим приоритетом, а потоки с меньшим приоритетом получают
процессорное время только тогда, когда их более привилегированные
собратья простаивают.
Работать с приоритетами потока можно с помощью двух функций:
void setPriority(int priority) – устанавливает приоритет потока.
Возможные значения priority — MIN_PRIORITY, NORM_PRIORITY и
MAX_PRIORITY.
int getPriority() – получает приоритет потока.
Некоторые полезные методы класса Thread

boolean isAlive() — возвращает true если myThready() выполняется и false


если поток еще не был запущен или был завершен.
setName(String threadName) – Задает имя потока.
String getName() – Получает имя потока.
Имя потока – ассоциированная с ним строка, которая в некоторых случаях
помогает понять, какой поток выполняет некоторое действие. Иногда это
бывает полезным.
static Thread Thread.currentThread() — статический метод, возвращающий
объект потока, в котором он был вызван.
long getId()– возвращает идентификатор потока. Идентификатор –
уникальное число, присвоенное потоку.
Завершение потоков

В Java существуют (существовали) средства для принудительного


завершения потока. В частности, метод Thread.stop() завершает поток
незамедлительно после своего выполнения. Однако этот метод, а также
Thread.suspend(), приостанавливающий поток, и Thread.resume(),
продолжающий выполнение потока, были объявлены устаревшими и их
использование отныне крайне нежелательно. Дело в том, что поток может
быть «убит» во время выполнения операции, обрыв которой на полуслове
оставит некоторый объект в неправильном состоянии, что приведет к
появлению трудноотлавливаемой и случайным образом возникающей
ошибке.
Завершение потоков

Вместо принудительного завершения потока применяется схема, в которой


каждый поток сам ответственен за своё завершение. Поток может
остановиться либо тогда, когда он закончит выполнение метода run(),
(main() — для главного потока) либо по сигналу из другого потока. Причем
как реагировать на такой сигнал — дело, опять же, самого потока. Получив
его, поток может выполнить некоторые операции и завершить выполнение,
а может и вовсе его проигнорировать и продолжить выполняться.
Описание реакции на сигнал завершения потока лежит на плечах
программиста.
Завершение потоков

Java имеет встроенный механизм оповещения потока, который называется


Interruption (прерывание, вмешательство), и скоро мы его рассмотрим, но
сначала посмотрите на следующую программку:
Incremenator — поток, который каждую секунду прибавляет или вычитает
единицу из значения статической переменной Program.mValue.
Incremenator содержит два закрытых поля – mIsIncrement и mFinish. То,
какое действие выполняется, определяется булевой переменной
mIsIncrement — если оно равно true, то выполняется прибавление
единицы, иначе — вычитание. А завершение потока происходит, когда
значение mFinish становится равно true.
Завершение потоков

class Incremenator extends Thread{


private volatile boolean mIsIncrement = true;
private volatile boolean mFinish = false; 
public void changeAction(){ //Меняет действие на противоположное
mIsIncrement = !mIsIncrement; }
public void finish(){ //Инициирует завершение потока
mFinish = true; } 
@Override
public void run(){
do{
if(!mFinish){//Проверка на необходимость завершения
if(mIsIncrement)
Program.mValue++; //Инкремент
else
Program.mValue--; //Декремент

//Вывод текущего значения переменной


Завершение потоков

//Вывод текущего значения переменной


System.out.print(Program.mValue + " ");}
else
return; //Завершение потока
  try{
Thread.sleep(1000); //Приостановка потока на 1 сек.
}catch(InterruptedException e){}}
while(true);}} 
public class Program{
//Переменая, которой оперирует инкременатор
public static int mValue = 0;
static Incremenator mInc; //Объект побочного потока
  public static void main(String[] args){
mInc = new Incremenator(); //Создание потока
System.out.print("Значение = ");
mInc.start(); //Запуск потока
Завершение потоков

//Троекратное изменение действия инкременатора


//с интервалом в i*2 секунд
for(int i = 1; i <= 3; i++){
try{
Thread.sleep(i*2*1000); //Ожидание в течении i*2 сек.
}catch(InterruptedException e){}
mInc.changeAction();} //Переключение действия
mInc.finish();}} //Инициация завершения побочного потока

Консоль:
Значение = 1 2 1 0 -1 -2 -1 0 1 2 3 4
 
Завершение потоков

Взаимодействовать с потоком можно с помощью метода changeAction()


(для смены вычитания на сложение и наоборот) и метода finish() (для
завершения потока).
В объявлении переменных mIsIncrement и mFinish было использовано
ключевое слово volatile (изменчивый, не постоянный). Его необходимо
использовать для переменных, которые используются разными потоками.
Это связано с тем, что значение переменной, объявленной без volatile,
может кэшироваться отдельно для каждого потока, и значение из этого
кэша может различаться для каждого из них. Объявление переменной с
ключевым словом volatile отключает для неё такое кэширование и все
запросы к переменной будут направляться непосредственно в память.
 
Завершение потоков

В примере показано, каким образом можно организовать взаимодействие


между потоками. Однако есть одна проблема при таком подходе к
завершению потока — Incremenator проверяет значение поля mFinish раз в
секунду, поэтому может пройти до секунды времени между тем, когда
будет выполнен метод finish(), и фактическим завершения потока. Было бы
замечательно, если бы при получении сигнала извне, метод sleep()
возвращал выполнение и поток незамедлительно начинал своё завершение.
Для выполнения такого сценария существует встроенное средство
оповещения потока, которое называется Interruption (прерывание,
вмешательство). 
Interruption

Класс Thread содержит в себе скрытое булево поле, подобное полю mFinish в
программе Incremenator, которое называется флагом прерывания. Установить этот флаг
можно вызвав метод interrupt() потока. Проверить же, установлен ли этот флаг, можно
двумя способами.

Первый способ — вызвать метод bool isInterrupted() объекта потока, второй — вызвать
статический метод bool Thread.interrupted(). Первый метод возвращает состояние флага
прерывания и оставляет этот флаг нетронутым.

Второй метод возвращает состояние флага и сбрасывает его. Thread.interrupted() —


статический метод класса Thread, и его вызов возвращает значение флага прерывания
того потока, из которого он был вызван. Поэтому этот метод вызывается только изнутри
потока и позволяет потоку проверить своё состояние прерывания.
Interruption

У методов, приостанавливающих выполнение потока, таких как sleep(), wait() и join()


есть одна особенность — если во время их выполнения будет вызван метод interrupt()
этого потока, они, не дожидаясь конца времени ожидания, сгенерируют исключение
InterruptedException.

class Incremenator extends Thread{


private volatile boolean mIsIncrement = true;
public void changeAction(){ //Меняет действие на противоположное
mIsIncrement = !mIsIncrement; }
@Override
public void run() {
do{
if(!Thread.interrupted()){ //Проверка прерывания

if(mIsIncrement) Program.mValue++; //Инкремент


else Program.mValue--; //Декремент
Interruption
if(mIsIncrement) Program.mValue++; //Инкремент
else Program.mValue--; //Декремент
//Вывод текущего значения переменной
System.out.print(Program.mValue + " ");}
else
return; //Завершение потока
try{
Thread.sleep(1000); //Приостановка потока на 1 сек.
}catch(InterruptedException e){
return;}} //Завершение потока после прерывания
while(true); }}
class Program{
//Переменая, которой оперирует инкременатор
public static int mValue = 0;
static Incremenator mInc; //Объект побочного потока

public static void main(String[] args)


Interruption
public static void main(String[] args){
mInc = new Incremenator(); //Создание потока
System.out.print("Значение = ");
mInc.start(); //Запуск потока
//Троекратное изменение действия инкременатора
//с интервалом в i*2 секунд
for(int i = 1; i <= 3; i++) {
try{
Thread.sleep(i*2*1000); //Ожидание в течении i*2 сек.
}catch(InterruptedException e){}
mInc.changeAction();} //Переключение действия
mInc.interrupt(); }}//Прерывание побочного потока

Консоль:
Значение = 1 2 1 0 -1 -2 -1 0 1 2 3 4
Interruption

Реализован тот же механизм завершения потока с помощью встроенной


системы прерываний. В этой реализации одно преимущество — метод
sleep() вернет управление (сгенерирует исключение) незамедлительно
после прерывания потока.

Методы sleep() и join() обёрнуты в конструкции try-catch. Это необходимое


условие работы этих методов. Вызывающий их код должен перехватывать
исключение InterruptedException, которое они бросают при прерывании во
время ожидания.
Ключевое слово syncronized - синхронизированные методы

Для решения проблемы с потоками, которые могут внести путаницу, используется


синхронизация.
Метод может иметь модификатор syncronized. Когда поток находится внутри
синхронизированного метода, все другие потоки, которые пытаются вызвать его в том
же экземпляре, должны ожидать. Это позволяет исключить путаницу, когда несколько
потоков пытаются вызвать метод.

syncronized void meow(String msg);

Кроме того, ключевое слово syncronized можно использовать в качестве оператора. Вы


можете заключить в блок syncronized вызовы методов какого-нибудь класса:
syncronized(объект) {
// операторы, требующие синхронизации
}
Looper

Поток имеет в своём составе сущности Looper, Handler, MessageQueue.


Каждый поток имеет один уникальный Looper и может иметь много
Handler.
Looper - вспомогательный объект потока, который управляет им. Он
обрабатывает входящие сообщения, а также даёт указание потоку
завершиться в нужный момент.
Поток получает свой Looper и MessageQueue через метод Looper.prepare()
после запуска. Looper.prepare() идентифицирует вызывающий потк, создаёт
Looper и MessageQueue и связывает поток с ними в хранилище
ThreadLocal. Метод Looper.loop() следует вызывать для запуска Looper.
Завершить его работу можно через метод looper.quit().
Looper

int[] array = new int[10];


for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random()*100);
}
int minValue = array[0];
for (int j=0; j < array.length; j++){
for(int i = j + 1; i < array.length; i++){
if(array[j] < array[i]){
int temp = (int) array[i];
array[i] = array[j];
array[j] = temp; } } }
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
Обработка исключительных событий

Возникновение ошибок и непредвиденных ситуаций при выполнении программы


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

Обработка исключений в Java основана на использовании в программе следующих


ключевых слов:
try – определяет блок кода, в котором может произойти исключение;
catch – определяет блок кода, в котором происходит обработка исключения;
finally – определяет блок кода, который является необязательным, но при его наличии
выполняется в любом случае независимо от результатов выполнения блока try.
Эти ключевые слова используются для создания в программном коде специальных
обрабатывающих конструкций: try{}catch, try{}catch{}finally, try{}finally{}.
throw – используется для возбуждения исключения;
throws – используется в сигнатуре методов для предупреждения, о том, что метод
может выбросить исключение.
Обработка исключительных событий

Операторы программы, которые вы хотите отслеживать, помещаются в блок try. Если


исключение произошло, то оно создаётся и передаётся дальше. Ваш код может
перехватить исключение при помощи блока catch и обработать его. Системные
исключения автоматически передаются самой системой. Чтобы передать исключение
вручную, используется throw. Любое исключение, созданное и передаваемое внутри
метода, должно быть указано в его интерфейсе ключевым словом throws. Любой код,
который следует выполнить обязательно после завершения блока try, помещается в
блок finally.
Обработка исключительных событий

try {
// блок кода, где отслеживаются ошибки
}
catch (тип_исключения_1 exceptionObject) {
// обрабатываем ошибку
}
catch (тип_исключения_2 exceptionObject) {
// обрабатываем ошибку
}
finally {
// код, который нужно выполнить после завершения блока try
}
Обработка исключительных событий

Существует специальный класс для исключений Throwable. В него входят два класса
Exception и Error.

Класс Exception используется для обработки исключений вашей программой. Вы


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

Класс Error служит для обработки ошибок в самом языке Java и на практике вам не
придётся иметь с ним дело.
Несколько исключений

Фрагмент кода может содержать несколько проблемных мест. Например,


кроме деления на ноль, возможна ошибка индексации массива. В таком
случае вам нужно создать два или более операторов catch для каждого типа
исключения. Причём они проверяются по порядку. Если исключение будет
обнаружено у первого блока обработки, то он будет выполнен, а остальные
проверки пропускаются и выполнение программы продолжается с места,
который следует за блоком try/catch.
Несколько исключений

int catNumber;
int zero;
try { // мониторим код
catNumber = 1; // у меня один кот
zero = 1; // ноль, он и в Африке ноль
int result = catNumber / zero;
// Создадим массив из трёх котов
String[] catNames = {"Васька", "Барсик", "Мурзик"};
catNames[3] = "Рыжик";
Toast.makeText(this, "Не увидите это сообщение!", Toast.LENGTH_LONG).show();
} catch (ArithmeticException e) {
Toast.makeText(this, e.toString() + ": Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}
catch (ArrayIndexOutOfBoundsException e) {
Toast.makeText(this, "Ошибка: " + e.toString(), Toast.LENGTH_LONG).show();}
Toast.makeText(this, "Жизнь продолжается", Toast.LENGTH_LONG).show();
Несколько исключений

Массив состоит из трех элементов, но обращение происходит к четвёртому элементу.


Если оставить значение переменной zero равным нулю, то сработает обработка первого
исключения деления на ноль, и мы даже не узнаем о существовании второй ошибки. Но
допустим, что в результате каких-то вычислений значение переменной стало равно
единице. Тогда наше исключение ArithmeticException не сработает. Но сработает новое
добавленное исключение ArrayIndexOutOfBoundsException.
При использовании множественных операторов catch обработчики подклассов
исключений должные находиться выше, чем обработчики их суперклассов. Иначе,
суперкласс будет перехватывать все исключения, имея большую область перехвата.
Иными словами, Exception не должен находиться выше ArithmeticException и
ArrayIndexOutOfBoundsException. К счастью, среда разработки сама замечает
непорядок и предупреждает вас, что такой порядок не годится.
Оператор throw

Часть исключений может обрабатывать сама система. Но можно создать


собственные исключения при помощи оператора throw. Код выглядит так:
throw экземпляр_Throwable
Создается экземпляр класса Throwable или его наследников. Получить
объект класса Throwable можно в операторе catch или стандартным
способом через оператор new.

Cat cat;
public void onClick(View view) {
if(cat == null){
throw new NullPointerException("Кот не инициализирован");}}
Оператор throw

Был объявлен объект класса Cat, но не проинициализирован, например, в


onCreate(). Теперь нажатие кнопки вызовет исключение, которое
обработает система, а в логах будет сообщение об ошибке. Можно
использовать другое исключение, например, throw new
UnsupportedOperationException("Кот не инициализирован");.

В реальном приложении нужно обработать ошибку самостоятельно.

Поток выполнения останавливается непосредственно после оператора


throw и другие операторы не выполняются. При этом ищется ближайший
блок try/catch соответствующего исключению типа.
Оператор throw

public void onClick(View view) {


if (cat == null) {
try {
throw new NullPointerException("Кота не существует");
} catch (NullPointerException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
Оператор throw

Создается новый объект класса NullPointerException. Многие классы


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

Теперь программа не закроется аварийное, а будет просто выводить


сообщения в всплывающих Toast.
Оператор throws
Если метод может породить исключение, которое он сам не обрабатывает,
он должен задать это поведение так, чтобы вызывающий его код мог
позаботиться об этом исключении. Для этого к объявлению метода
добавляется конструкция throws, которая перечисляет типы исключений
(кроме исключений Error и RuntimeException и их подклассов).

Общая форма объявления метода с оператором throws:

тип имя_метода(список_параметров) throws список_исключений {


// код внутри метода}
В фрагменте список_исключений можно указать список исключений через
запятую.
Оператор throws
public void createCat() throws NullPointerException {
Toast.makeText(this, "Вы создали котёнка",
Toast.LENGTH_LONG).show();
throw new NullPointerException("Кота не существует");}
// Щелчок кнопки
public void onClick(View v) {
try {
createCat();
} catch (NullPointerException e) {
// TODO: handle exception
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();}}
Оператор finally

Когда исключение передано, выполнение метода направляется по


нелинейному пути. Это может стать источником проблем. Например, при
входе метод открывает файл и закрывает при выходе. Чтобы закрытие
файла не было пропущено из-за обработки исключения, был предложен
механизм finally.

Ключевое слово finally создаёт блок кода, который будет выполнен после
завершения блока try/catch, но перед кодом, следующим за ним. Блок будет
выполнен, независимо от того, передано исключение или нет. Оператор
finally не обязателен, однако каждый оператор try требует наличия либо
catch, либо finally.
Встроенные исключения Java

Существуют несколько готовых системных исключений. Большинство из


них являются подклассами типа RuntimeException и их не нужно включать
в список throws. Вот небольшой список непроверяемых исключений.
• ArithmeticException - арифметическая ошибка, например, деление на нуль
• ArrayIndexOutOfBoundsException - выход индекса за границу массива
• ArrayStoreException - присваивание элементу массива объекта несовместимого типа
• ClassCastException - неверное приведение
• EnumConstantNotPresentException - попытка использования неопределённого
значения перечисления
Встроенные исключения Java

• IllegalArgumentException - неверный аргумент при вызове метода


• IllegalMonitorStateException - неверная операция мониторинга
• IllegalStateException - некорректное состояние приложения
• IllegalThreadStateException - запрашиваемая операция несовместима с текущим
потоком
• IndexOutofBoundsException - тип индекса вышел за допустимые пределы
• NegativeArraySizeException - создан массив отрицательного размера
• NullPointerException - неверное использование пустой ссылки
• NumberFormatException - неверное преобразование строки в числовой формат
• SecurityException - попытка нарушения безопасности
• StringIndexOutOfBounds - попытка использования индекса за пределами строки
• TypeNotPresentException - тип не найден
• UnsupportedOperationException - обнаружена неподдерживаемая операция
Встроенные исключения Java

Список проверяемых системных исключений, которые можно включать в список


throws.
• ClassNotFoundException - класс не найден
• CloneNotSupportedException - попытка клонировать объект, который не реализует
интерфейс Cloneable
• IllegalAccessException - запрещен доступ к классу
• InstantiationException - попытка создать объект абстрактного класса или интерфейса
• InterruptedException - поток прерван другим потоком
• NoSuchFieldException - запрашиваемое поле не существует
• NoSuchMethodException - запрашиваемый метод не существует
• ReflectiveOperationException - исключение, связанное с рефлексией
Создание собственных классов исключений

Система не может предусмотреть все исключения, иногда вам придётся


создать собственный тип исключения для вашего приложения. Вам нужно
наследоваться от Exception (напомню, что этот класс наследуется от
Trowable) и переопределить нужные методы класса Throwable. Либо вы
можете наследоваться от уже существующего типа, который наиболее
близок по логике с вашим исключением.
• final void addSuppressed(Throwable exception) - добавляет исключение в список
подавляемых исключений (JDK 7)
• Throwable fillInStackTrace() - возвращает объект класса Throwable, содержащий
полную трассировку стека.
• Throwable getCause() - возвращает исключение, лежащее под текущим исключение
или null
Создание собственных классов исключений

• String getLocalizedMessage() - возвращает локализованное описание исключения


• String getMessage() - возвращает описание исключения
• StackTraceElement[] getStackTrace() - возвращает массив, содержащий трассировку стека и состояний
из элементов класса StackTraceElement
• final Throwable[] getSuppressed() - получает подавленные исключения (JDK 7)
• Throwable initCause(Throwable exception) - ассоциирует исключение с вызывающим исключением.
Возвращает ссылку на исключение.
• void printStackTrace() - отображает трассировку стека
• void printStackTrace(PrintStream stream) - посылает трассировку стека в заданный поток
• void printStackTrace(PrintWriter stream) - посылает трассировку стека в заданный поток
• void setStackTrace(StackTraceElement elements[]) - устанавливает трассировку стека для элементов
(для специализированных приложений)
• String toString() - возвращает объект класса String, содержащий описание исключения.
Перехват произвольных исключений

Можно создать универсальный обработчик, перехватывающий любые


типы исключения. Осуществляется это перехватом базового класса всех
исключений Exception:
cacth(Exception e) {
Log.w("Log", "Перехвачено исключение");
}
Подобная конструкция не упустит ни одного исключения, поэтому её
следует размещать в самом конце списка обработчиков, во избежание
блокировки следующих за ней обработчиков исключений.
Основные правила обработки исключений

Используйте исключения для того, чтобы:


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

• сделать все возможное в текущем контексте и заново возбудить это же


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

//метод считывает строку с клавиатуры

public String input() throws MyException {//предупреждаем с помощью throws,


// что метод может выбросить исключение MyException
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = null;
//в блок try заключаем код, в котором может произойти исключение, в данном
// случае компилятор нам подсказывает, что метод readLine() класса
// BufferedReader может выбросить исключение ввода/вывода
try {
s = reader.readLine();
// в блок catch заключаем код по обработке исключения IOException
} catch (IOException e) {
System.out.println(e.getMessage());
// в блоке finally закрываем поток чтения
Пример обработки исключений

} finally {
// при закрытии потока тоже возможно исключение, например, если он не был открыт, поэтому
“оборачиваем” код в блок try
try {
reader.close();
// пишем обработку исключения при закрытии потока чтения
} catch (IOException e) {
System.out.println(e.getMessage());}}

if (s.equals("")) {
// мы решили, что пустая строка может нарушить в дальнейшем работу нашей программы, например, на
результате этого метода нам надо вызывать метод substring(1,2), поэтому мы вынуждены прервать
выполнение программы с генерацией своего типа исключения MyException с помощью throw
throw new MyException("String can not be empty!"); }
return s;}
Принципы построения графического интерфейса

Компонент и контейнер

Основное понятие графического интерфейса пользователя (ГИП) – компонент


графической системы. Компонент – это полностью определенный элемент, который
можно использовать в графическом интерфейсе независимо от других элементов (поле
ввода, кнопка, строка меню, полоса прокрутки и пр.). Само окно приложения – тоже его
компонент. Компоненты могут быть и невидимыми.
Класс Component, в котором собраны общие методы работы с любым компонентом
графического интерфейса пользователя – цент библиотеки AWT.
Каждый компонент перед выводом на экран, помещается в контейнер. Контейнер знает,
как поместить компоненты на экра. В языке Java контейнер – это объект класса
Container или всякого его расширения. Прямой наследник этого класса – класс
JComponent – вершина иерархии многих компонентов библиотеки Swing.
Принципы построения графического интерфейса

Создав компонент – объект класса Component или его расширения, следуте добавить
его к предварительно созданному объекта класса Container или его расширения одним
из методов контейнера add().
Класс Container сам является невидимым компонентом, он расширяет класс Component.
Таким образом, в контейнер наряду с компонентами можно помещать контейнеры, в
которых находятся какие-то другие компоненты, достигая тем самым большой
гибкости расположения компонентов.
Основное окно приложения, активно взаимодействующиее с операционной системой,
необходимо построить по правилам её графической системы. Око должно
перемещаться по экрану, изменять размеры, реагировать на действия мыши и
клавиатуры.
Принципы построения графического интерфейса

В окне должны быть как минимум следующие стандартные компоненты:


1. строка заголовка (title bar), с левой стороны которой необходимо поместить кнопку контекстного
меню, а с правой – кнопки сворачивания и разворачивания окна и кнопку закрытия приложения.
2. окно должно быть окружено рамкой, реагирующей на действия мыши.
Окно с этими компонентами описано в готовом виде в классе Frame. Чтобы создать окно в библиотеке
AWT, достаточно сделать свой класс расширением класса Frame.
import java.awt.*;
import java.awt.event.*;
public class SimpleFr1 extends Frame {
SimpleFr1 (String s){
super(s);
setSize(400,150);
setVisible(true);
addWindowListener (new WindowAdapter(){
public void windowClosing (WindowEvent ev){
System.exit(0);}}); }
public static void main(String[] args) {
new SimpleFr1 ("New Ghjuh"); }
Основные компоненты Swing

В библиотеку Swing входит около тридцати готовых графических компонентов –


надписи, кнопки, поля ввода, ползунки, линейки прокрутки, ползунки, меню, таблицы.
В основном они собраны в пакет javax.swing.

Компонент JComponent
Основные свойства всех компонентов Swing сосредоточены в их суперклассе
JComponent. Класс JComponent расширяет класс Container, входящий в графическую
библиотеку AWT. Поэтому компонент JComponent и все его расширения являются
контейнерами и могут содержать в себе другие компоненты. Класс Container, в свою
очередь, расширяет класс Component, содержащий около сотни методов работы с
компонентами. Эти методы и методы класса Container наследуются классом
JComponent, который добавляет к ним добрую сотню своих методов. Все компоненты
Swing расширяют класс JComponent, наследуя его богатейшие свойства. Класс
JComponent – это абстрактный класс, поэтому нельзя создать его экземпляры.
Схема MVC в компонентах Swing

Конструктивная схема MVC (Model-View-Controller). Первая часть Model,


составляет один или несколько классов, в которых хранится или
вырабатывается вся информация, обрабатываемая компонентом, и текущее
состояние объектов, созданных этим компонентом. Эти классы обладают
методами setXXX() ввода и изменения информации.
Вторая часть – один или несколько классов, составляющих View. Эта часть
компоненота описывает способ представления результатов,
сгенерированных Моделью, на экране дисплея, принтере, или другом
устройстве в определенном виде: таблица, график, диаграмма. К одной
Модели можно подключить несколько Видов, по-разному предстваляющих
одни и те же результаты или отражающие разную информацию. Виды
получают информацию методами getXxx() и isXxx() Модели.
Схема MVC в компонентах Swing

Третья часть – классы, образующие Controller, - создают интерфейс для ввода


информации и изменения состояния объекта. Они реагируют на события ввода с
клавиатуры, действия мыши и прочие воздействия на объект и обращаются к методам
setXxx() Модели, изменяя её поля или вызывая генерацию информации. Одна Модель
может использоваться несколькими Контроллерами.
Вид и Контроллер не взаимодействуют. Контроллер, реагируя на события, обращается к
методам setXxx() Модели, которые меняют хранящуюся в ней информацию. Модель,
изменив информацию, сообщает об этом тем Видам, которые зарегистрировались у нее.
Это способ взаимодействия Модели и Вида получил название «подписка-рассылка».
Виды подписываются у Модели, и та рассылает им сообщения о всяком изменении
состояния объекта методами fireXxx(), после чего Виды забирают измененную
информацию, обращаясь к методам getXxx() и isXxx() Модели.
Схема MVC в компонентах Swing

В библиотеке Swing модели описаны интерфейсами, в которых перечислены


необходимые методы. У каждого интерфейса есть хотя бы одна стандартная
реализация, принимаемая компонентами Swing по умолчанию. Некоторые классы
реализуют сразу несколько интерфейсов, некоторые интерфейсы реализованы
несколькими классами.
Для реализации модели MVC библиотека Swing использует делегирование
полномочий, назначая в качестве методов данных представителя – экземпляр класса с
именем вида хххModel. Класс, описывающий компонент, содержит защищенное или
даже закрытое поле model – объект этого класса-модели, и метод getModel(),
предоставляющий разработчику доступ к полю model. Сложные компоненты могут
иметь несколько моделей.
class String

1. Класс реализует интерфейсы Serializable и CharSequence. Поскольку он входит в


пакет java.lang, его не нужно импортировать.

2. Класс String в Java — это final класс, который не может иметь потомков.

3. Класс String — immutable класс, то есть его объекты не могут быть изменены после
создания. Любые операции над объектом String, результатом которых должен быть
объект класса String, приведут к созданию нового объекта.

4. Благодаря своей неизменности, объекты класса String являются потокобезопасными


и могут быть использованы в многопоточной среде.

5. Каждый объект в Java может быть преобразован в строку через метод toString,
унаследованный всеми Java-классами от класса Object.
Операции со строками. class String
Создание строки

String s = "I love movies";

Однако у класса String есть много конструкторов, которые позволяют:


- создать объект, содержащий пустую строку
- создать копию строковой переменной
- создать строку на основе массива символов
- создать строку на основе массива байтов (с учетом кодировок)
и т.д.
Операции со строками. class String
Сложение строк

Java позволяет складывать друг с другом и переменные, и строковые


литералы:
public static void main(String[] args) {
String day = "День";
String and = "и";
String night = "Ночь";
String dayAndNight = day + " " + and + " " + night;}
Складывая объекты класса String с объектами других классов, мы
приводим последние к строковому виду. Преобразование объектов других
классов к строковому представлению выполняется через неявный вызов
метода toString у объекта.
Операции со строками. class String
Сравнение строк

Для сравнения строк можно воспользоваться методом equals():


public static void main(String[] args) {
String x = "Test String";
System.out.println("Test String".equals(x)); // true
}
Когда при сравнении строк нам не важен регистр, нужно использовать
метод equalsIgnoreCase():
public static void main(String[] args) {
String x = "Test String";
System.out.println("test string".equalsIgnoreCase(x)); // true
}
Операции со строками. class String
Перевод объекта/примитива в строку

Для перевода экземпляра любого Java-класса или любого примитивного


типа данных к строковому представлению, можно использовать метод
String.valueOf():
public class StringExamples {
public static void main(String[] args) {
String a = String.valueOf(1);
String b = String.valueOf(12.0D);
String c = String.valueOf(123.4F);
String d = String.valueOf(123456L);
String s = String.valueOf(true);
Операции со строками. class String
Перевод строки в число

Часто бывает нужно перевести строку в число. У классов оберток


примитивных типов есть методы, которые служат как раз для этой цели.
Все эти методы начинаются со слова parse. Рассмотрим ниже перевод
строки в целочисленное (Integer) и дробное (Double) числа:
public static void main(String[] args) {
Integer i = Integer.parseInt("12");
Double d = Double.parseDouble("12.65D");
System.out.println(i); // 12
System.out.println(d); // 12.65
}
Операции со строками. class String
Перевод коллекции строк к строковому представлению

Если нужно преобразовать все элементы некоторой коллекции строк к


строковому представлению через произвольный разделитель, можно
использовать такие методы класса String:

join(CharSequence delimiter, CharSequence... elements)


join(CharSequence delimiter, Iterable<? extends CharSequence> elements)

Где delimiter — разделитель элементов, а elements — массив строк /


экземпляр коллекции строк.
Операции со строками. class String
Разбиение строки на массив строк
Эту операцию выполняет метод split(String regex)

В качестве разделителя выступает строковое регулярное выражение regex.


public static void main(String[] args) {
String people = "Philip J. Fry; Turanga Leela";
String[] peopleArray = people.split("; ");
for (String human : peopleArray) {
System.out.println(human); }
}
Операции со строками. class String
Определение позиции элемента в строке
Набор методов для определения позиции символа/подстроки в строке:
indexOf(int ch)
indexOf(int ch, int fromIndex)
indexOf(String str)
indexOf(String str, int fromIndex)
lastIndexOf(int ch)
lastIndexOf(int ch, int fromIndex)
lastIndexOf(String str)
lastIndexOf(String str, int fromIndex)
Где:
ch — искомый символ (char)
str — искомая строка
fromIndex — позиция с которой нужно искать элемент
методы indexOf — возвращают позицию первого найденного элемента
методы lastIndexOf — возвращают позицию последнего найденного элемента
Операции со строками. class String
Определение позиции элемента в строке
Если искомый элемент не найден, методы вернут в строке -1.

Попробуем найти порядковый номер букв A, K, Z, Я в английском алфавите, но будем


иметь ввиду, что индексация символов в строке в Java начинается с нуля:

public static void main(String[] args) {


String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
System.out.println(alphabet.indexOf('A')); // 0
System.out.println(alphabet.indexOf('K')); // 10
System.out.println(alphabet.indexOf('Z')); // 25
System.out.println(alphabet.indexOf('Я')); // -1
}
Операции со строками. class String
Извлечение подстроки из строки

Для извлечения подстроки из строки класс String в Java предоставляет методы:


substring(int beginIndex)
substring(int beginIndex, int endIndex)
Рассмотрим, как с помощью методов определения позиции элемента и извлечения
подстроки мы можем получить имя файла из его пути:

public static void main(String[] args) {


String filePath = "D:\\Movies\\Futurama.mp4";
int lastFileSeparatorIndex = filePath.lastIndexOf('\\');
String fileName = filePath.substring(lastFileSeparatorIndex + 1);
System.out.println(fileName); //9
}
Операции со строками. class String
Перевод строки в верхний/нижний регистр

Класс String предоставляет методы для перевода строки в верхний и


нижний регистры:
toLowerCase()
toUpperCase()
Класс Vector
java.util 
public class Vector
extends AbstractList
implements List, Cloneable, Serializable
Vector — это способный увеличивать число своих элементов массив
ссылок на объекты. Внутри себя Vector реализует стратегию
динамического расширения, позволяющую минимизировать
неиспользуемую память и количество операций по выделению памяти.

Объявление:
Vector NewVec1 = new Vector();
Конструкторы класса Vector
Vector()
Создаёт пустой вектор размером 10 и с capacityIncrement = 0.

Vector(Collection c)
Создаёт вектор содержащий элементы определённой коллекции.

Vector(int initialCapacity)
Создает пустой вектор с заданным объемом памяти.

Vector(int initialCapacity, int capacityIncrement)


Создает пустой вектор с заданным объемом памяти (initialCapacity) и
увеличением объема (capacityIncrement).
Методы класса Vector
void add(int index, Object element)
Добавляет в определённую позицию вектора определённый элемент.

boolean add(Object o)
Добавляет в конец вектора определённый элемент.

boolean addAll(Collection c)
Добавляет в вектор все элементы определённой коллекции.

boolean addAll(int index, Collection c)


Добавляет в вектор в определённую позицию все элементы коллекции.

void addElement(Object obj)


Добавляет определённый компонент в конец вектора, увеличивая размер вектора.
Методы класса Vector
int capacity() // Возвращает объем вектора.

void clear() // Удаляет все элементы вектора.

Object clone()
Возвращает аналог вектора.

boolean contains(Object elem)


Возвращает значение true если компонент содержится в векторе.

boolean containsAll(Collection c)
Возвращает значение true если вектор содержит все элементы коллекции.
Методы класса Vector
void copyInto(Object[] anArray)
Копирует элементы вектора в заданный массив.

Object elementAt(int index)


Возвращает компонент по индексу.

Enumeration elements()
Возвращает перечисление компонентов вектора.

void ensureCapacity(int minCapacity)


Увеличивает минимальный объём вектора.

boolean equals(Object o)
Сравнивает определённый объект с вектором.
Методы класса Vector
Object firstElement()
Возвращает первый элемент вектора (индекс 0).

Object get(int index)


Возвращает элемент вектора из определённой позиции.

int hashCode()
Возвращает хэш-код вектора.

int indexOf(Object elem)


Ищет аналог объекта и возвращает индекс первого найденого.
Методы класса Vector
int indexOf(Object elem, int index)
Ищет аналог объекта, начиная с определённой позиции, и возвращает индекс
первого найденого.

void insertElementAt(Object obj, int index)


Вставляет объект в определённую позицию в векторе.

boolean isEmpty()
Возвращает true если вектор пуст.

Object lastElement()
Возвращает поседний элемент вектора.
Методы класса Vector
int lastIndexOf(Object elem)
Возвращает индекс последнего найденного аналога объекта.

int lastIndexOf(Object elem, int index)


Возвращает индекс последнего найденного аналога объекта, начиная поиск с
определённой позиции.

Object remove(int index) // Удаляет объект из определённой позиции в векторе.

boolean remove(Object o) //Удаляет первый найденный аналогичный объект.

boolean removeAll(Collection c) //Удаляет все объекты коллекции в векторе.

void removeAllElements()//Удаляет все объекты и устанавливает размер равным нулю.


Методы класса Vector
boolean removeElement(Object obj)
Удаляет первый найденный аналогичный компонент.

void removeElementAt(int index)


Удаляет компонент из определённой позиции в векторе.

protected void removeRange(int fromIndex, int toIndex)


Удаляет все объекты, начиная с объекта с индексом fromIndex и заканчивая
объектом с индексом toIndex.

boolean retainAll(Collection c)
Удаляет все объекты кроме объектов содержащихся в коллекции.
Методы класса Vector
Object set(int index, Object element)
Заменяет объект в определянной позиции на другой.

void setElementAt(Object obj, int index)


Заменяет компонент в определянной позиции на другой.

void setSize(int newSize) // Устанавливает размер вектора.


int size() // Возвращает количество компонентов в векторе.
List subList(int fromIndex, int toIndex)
Возвращает часть вектора начиная с объекта с индексом fromIndex и заканчивая
объектом с индексом toIndex.

Object[] toArray()
Возвращает массив содержащий все элементы вектора.
Методы класса Vector
Object[] toArray(Object[] a)
Возвращает массив содержащий все элементы вектора.

String toString()
Возвращает представление вектора в виде строки.

void trimToSize()
Приводит объем вектора к заданному размеру.
Методы класса Vector

import java.util.Vector;
public class VectorExample {
Vector vector=new Vector();
public void addCharacterandPrint(){
vector.add("Weasley");
vector.add("Potter");
for(int i=0;i<vector.size();i++){
System.out.println("The characters are\t"+vector.get(i));
}
}
public static void main(String args[]){
VectorExample example=new VectorExample(); example.addCharacterandPrint();
}
}
Методы класса Vector

Класс vector является примером того, как можно объекты класса object , a значит,


любые объекты, объединить в коллекцию. Этот тип коллекции упорядочивает и даже
нумерует элементы. В векторе есть первый элемент, есть последний элемент. К
каждому элементу обращаются непосредственно по
индексу. При добавлении и удалении элементов оставшиеся элементы автоматически
перенумеровываются.
Класс Stack

Класс stack из пакета java.util. объединяет элементы в стек.

Стек ( stack) реализует порядок работы с элементами подобно магазину винтовки—


первым выстрелит патрон, положенный в магазин последним,— или подобно
железнодорожному тупику — первым из тупика выйдет вагон, загнанный туда
последним. Такой порядок обработки называется LIFO (Last In — First Out).

Перед работой создается пустой стек конструктором stack ().

Затем на стек кладутся и снимаются элементы, причем доступен только "верхний"


элемент, тот, что положен на стек последним.
Класс Stack

Дополнительно к методам класса vector класс stack содержит пять методов,


позволяющих работать с коллекцией как со стеком:

push (Object item) —помещает элемент item в стек;

pop () — извлекает верхний элемент из стека;

peek () — читает верхний элемент, не извлекая его из стека;

empty () — проверяет, не пуст ли стек;

search (object item) — находит позицию элемента item в стеке. Верхний элемент имеет
позицию 1, под ним элемент 2 и т. д. Если элемент не найден, возвращается — 1.
Класс Stack

import java.utii.*; 
class StackTesti
static boolean checkParity(String expression,
                    String open, String close){ 
   Stack stack = new Stack (); 
   StringTokenizer st = new StringTokenizer(expression,
                          " \t\n\r+*/-(){}", true);
   while (st..hasMoreTokens ()) {
     String tmp = st.nextToken();
     if (tmp.equals(open)) , stack.push(open);
           i f (tmp.equals(close)) stack.pop(); 
     }
     if (stack.isEmpty () ) return true/return fals e; 
}
public static void main(String[] args){ 
  System.out.println(
          checkParityC'a - (b - (c - a) / (b + c) - 2) , "(", "))); 
 } 
Коллекции.
Для хранения наборов данных в Java предназначены массивы. Однако их не всегда
удобно использовать, прежде всего потому, что они имеют фиксированную длину. Эту
проблему в Java решают коллекции. Однако суть не только в гибких по размеру наборах
объектов, но в и том, что классы коллекций реализуют различные алгоритмы и
структуры данных, например, такие как стек, очередь, дерево и ряд других.

Классы коллекций располагаются в пакете java.util, поэтому перед применением


коллекций следует подключить данный пакет.

Хотя в Java существует множество коллекций, но все они образуют стройную и


логичную систему. Во-первых, в основе всех коллекций лежит применение того или
иного интерфейса, который определяет базовый функционал.
Типы коллекций.
Collection: базовый интерфейс для всех коллекций и других интерфейсов коллекций

Queue: наследует интерфейс Collection и представляет функционал для структур данных в виде очереди

Deque: наследует интерфейс Queue и представляет функционал для двунаправленных очередей

List: наследует интерфейс Collection и представляет функциональность простых списков

Set: также расширяет интерфейс Collection и используется для хранения множеств уникальных объектов

SortedSet: расширяет интерфейс Set для создания сортированных коллекций

NavigableSet: расширяет интерфейс SortedSet для создания коллекций, в которых можно осуществлять поиск по
соответствию

Map: предназначен для созданий структур данных в виде словаря, где каждый элемент имеет определенный ключ и
значение. В отличие от других интерфейсов коллекций не наследуется от интерфейса Collection
Типы коллекций. Абстрактные классы.
Интерфейсы частично реализуются абстрактными классами:

AbstractCollection: базовый абстрактный класс для других коллекций, который применяет интерфейс Collection

AbstractList: расширяет класс AbstractCollection и применяет интерфейс List, предназначен для создания коллекций
в виде списков

AbstractSet: расширяет класс AbstractCollection и применяет интерфейс Set для создания коллекций в виде
множеств

AbstractQueue: расширяет класс AbstractCollection и применяет интерфейс Queue, предназначен для создания
коллекций в виде очередей и стеков

AbstractSequentialList: также расширяет класс AbstractList и реализует интерфейс List. Используется для создания
связанных списков

AbstractMap: применяет интерфейс Map, предназначен для создания наборов по типу словаря с объектами в виде
пары "ключ-значение"
Типы коллекций. Абстрактные классы.
С помощью применения вышеописанных интерфейсов и абстрактных классов в Java
реализуется широкая палитра классов коллекций - списки, множества, очереди,
отображения и другие, среди которых можно выделить следующие:

ArrayList: простой список объектов

LinkedList: представляет связанный список

ArrayDeque: класс двунаправленной очереди, в которой мы можем произвести вставку


и удаление как в начале коллекции, так и в ее конце

HashSet: набор объектов или хеш-множество, где каждый элемент имеет ключ -
уникальный хеш-код
Типы коллекций. Абстрактные классы.

TreeSet: набор отсортированных объектов в виде дерева

LinkedHashSet: связанное хеш-множество

PriorityQueue: очередь приоритетов

HashMap: структура данных в виде словаря, в котором каждый объект имеет


уникальный ключ и некоторое значение

TreeMap: структура данных в виде дерева, где каждый элемент имеет уникальный
ключ и некоторое значение
Интерфейс Collection

Интерфейс Collection является базовым для всех коллекций, определяя основной


функционал. Интерфейс Collection является обобщенным и расширяет интерфейс
Iterable, поэтому все объекты коллекций можно перебирать в цикле по типу for-each.

Наиболее важные методы интерфейса Collection:

boolean add (E item): добавляет в коллекцию объект item. При удачном добавлении
возвращает true, при неудачном - false

boolean addAll (Collection<? extends E> col): добавляет в коллекцию все элементы из
коллекции col. При удачном добавлении возвращает true, при неудачном - false

void clear (): удаляет все элементы из коллекции


Интерфейс Collection

boolean contains (Object item): возвращает true, если объект item содержится в
коллекции, иначе возвращает false

boolean isEmpty (): возвращает true, если коллекция пуста, иначе возвращает false

Iterator<E> iterator (): возвращает объект Iterator для обхода элементов коллекции

boolean remove (Object item): возвращает true, если объект item удачно удален из
коллекции, иначе возвращается false

boolean removeAll (Collection<?> col): удаляет все объекты коллекции col из текущей
коллекции. Если текущая коллекция изменилась, возвращает true, иначе возвращается
false
Интерфейс Collection

boolean retainAll (Collection<?> col): удаляет все объекты из текущей коллекции, кроме
тех, которые содержатся в коллекции col. Если текущая коллекция после удаления
изменилась, возвращает true, иначе возвращается false

int size (): возвращает число элементов в коллекции

Object[] toArray (): возвращает массив, содержащий все элементы коллекции


Интерфейс Collection

Все эти и остальные методы, которые имеются в интерфейсе Collection, реализуются


всеми коллекциями, поэтому в целом общие принципы работы с коллекциями будут
одни и те же. Единообразный интерфейс упрощает понимание и работу с различными
типами коллекций. Так, добавление элемента будет производиться с помощью метода
add, который принимает добавляемый элемент в качестве параметра. Для удаления
вызывается метод remove(). Метод clear будет очищать коллекцию, а метод size
возвращать количество элементов в коллекции.
Интерфейс List

Для создания простых списков применяется интерфейс List, который расширяет


функциональность интерфейса Collection. Методы интерфейса List:

void add(int index, E obj): добавляет в список по индексу index объект obj

boolean addAll(int index, Collection<? extends E> col): добавляет в список по индексу
index все элементы коллекции col. Если в результате добавления список был изменен,
то возвращается true, иначе возвращается false

E get(int index): возвращает объект из списка по индексу index

int indexOf(Object obj): возвращает индекс первого вхождения объекта obj в список.
Если объект не найден, то возвращается -1
Интерфейс List

int lastIndexOf(Object obj): возвращает индекс последнего вхождения объекта obj в


список. Если объект не найден, то возвращается -1

ListIterator<E> listIterator (): возвращает объект ListIterator для обхода элементов


списка

static <E> List<E> of(элементы): создает из набора элементов объект List

E remove(int index): удаляет объект из списка по индексу index, возвращая при этом
удаленный объект

E set(int index, E obj): присваивает значение объекта obj элементу, который находится
по индексу index
Интерфейс List

void sort(Comparator<? super E> comp): сортирует список с помощью компаратора


comp

List<E> subList(int start, int end): получает набор элементов, которые находятся в
списке между индексами start и end
Класс ArrayList

По умолчанию в Java есть встроенная реализация этого интерфейса - класс ArrayList.


Класс ArrayList представляет обобщенную коллекцию, которая наследует свою
функциональность от класса AbstractList и применяет интерфейс List. ArrayList
представляет простой список, аналогичный массиву, за тем исключением, что
количество элементов в нем не фиксировано.

ArrayList(): создает пустой список

ArrayList(Collection <? extends E> col): создает список, в который добавляются все
элементы коллекции col.

ArrayList (int capacity): создает список, который имеет начальную емкость capacity
Класс ArrayList

Емкость в ArrayList представляет размер массива, который будет использоваться для


хранения объектов. При добавлении элементов фактически происходит
перераспределение памяти - создание нового массива и копирование в него элементов
из старого массива. Изначальное задание емкости ArrayList позволяет снизить
подобные перераспределения памяти, тем самым повышая производительность.
Класс ArrayList
import java.util.ArrayList; 
public class Program{      
    public static void main(String[] args) {          
        ArrayList<String> people = new ArrayList<String>();
        // добавим в список ряд элементов
        people.add("Tom");
        people.add("Alice");
        people.add("Kate");
        people.add("Sam");
        people.add(1, "Bob"); // добавляем элемент по индексу 1          
        System.out.println(people.get(1));// получаем 2-й объект
        people.set(1, "Robert"); // установка нового значения для 2-го объекта          
        System.out.printf("ArrayList has %d elements \n", people.size());
        for(String person : people){          
            System.out.println(person);        }
        // проверяем наличие элемента
        if(people.contains("Tom")){          
            System.out.println("ArrayList contains Tom");
        }
Класс ArrayList
       // удалим несколько объектов
        // удаление конкретного элемента
        people.remove("Robert");
        // удаление по индексу
        people.remove(0);
          
        Object[] peopleArray = people.toArray();
        for(Object person : peopleArray){
          
            System.out.println(person);
        }
    }
}
Java + SQL

Подавляющее большинство баз данных являются МНОГОПОЛЬЗОВАТЕЛЬСКИМИ.


Проблема базы данных в виде обычного файла заключается в том, что к этому файлу
будет обращаться сразу много программ, каждая из которых захочет внести изменения
или получить данные. Организовать такой доступ на уровне файловой системы — по
сути, невыполнимая задача:
1.файл должен быть доступен всем пользователям, что требует перекачку данных по
сети и хранение этого файла где-то на сетевом диске. Большие объемы данных по сети,
передаваемые даже с высокой скоростью чрезвычайно небезопасное и ненадежное
дело.
2.Во-вторых — попытка одновременной записи в файл несколькими программами
обречена на провал. Для организации такого доступа обычной файловой системы явно
не достаточно.
3.Организация прав доступа к тем или иным данным становится непосильной задачей.
4. Возникнут конфликты с доступом к одним и тем же данным.
Java + SQL

После небольшого анализа, кроме этих вопросов, можно увидеть еще немалое
количество проблем, которые надо решить при мультипользовательском доступе к
данным.
В итоге было принято (и реализовано) вполне здравое решение — написать
специальную программу, которая называется — Система Управления Базами Данных
(СУБД).
Суть и цель этой программы — организовать централизованный доступ к данным. Т.е.
все запросы на получение или изменение данных от клиентских приложений
(клинетов) посылаются (обычно по сети и по протоколу TCP/IP) именно в эту
программу. И уже эта программа будет заниматься всеми вышеупомянутыми
проблемами.
Java + SQL

1. СУБД будет иметь некоторый набор команд, который позволит записывать и


получать данные
2. СУБД будет сама работать с файловой системой (нередко у нее бывает своя
собственная файловая система для скорости)
3. СУБД предоставит механизмы разграничения доступа к разным данным
4. СУБД будет решать задачи одновременного доступа к данным
В итоге мы получаем достаточно ясную архитектуру — есть СУБД, которая
сосредоточена на работе с данными и есть клиенты, которые могут посылать запросы к
СУБД.
Java + SQL
Java + SQL

При работе с СУБД клиенты должны решить достаточно четкие задачи:


1. Клиент должен соединиться с СУБД. Как я уже упоминал, чаще всего
для общения используется сетевой протокол TCP/IP. В момент
подключения клиент также передает свой логин/пароль, чтобы СУБД
могла его идентифицировать и в дальнейшем позволить (или не позволить)
производить те или иные действия над данными
2. Клиент может посылать команды для изменения/получения данных в
СУБД
3. Данные внутри СУБД хранятся в определенных структурах и к этим
структурам можно обратиться через команды
JDBC — Java Database Connectivity — архитектура
JDBC представляет собой описание интерфейсов и некоторых классов, которые
позволяют работать с базами данных из Java.
Главным принципом архитектуры является унифицированный (универсальный,
стандартный) способ общения с разными базами данных. Т.е. с точки зрения
приложения на Java общение с Oracle или MySQL не должно отличаться. По
возможности совсем не должно отличаться.
Сами SQL-запросы могут отличаться за счет разного набора функций для дат, строк и
других. Но это уже строка запроса другая, а алгоритм и набор команд для доставки
запроса на SQL-сервер и получение данных от SQL-сервера отличаться не должны.
Приложение не должно думать над тем, с какой базе оно работает — все базы должны
выглядеть одинаково. При этом внутреннее устройство передачи данных для разных
СУБД разное. Правила передачи байтов для Oracle отличается от правил передачи
байтов для MySQL. В итоге — с одной стороны все выглядят одинаково, но с другой
реализации будут разные. Вопрос разрешается через полиморфизм через интерфейсы.
Именно на этом и строится архитектура JDBC.
JDBC — Java Database Connectivity — архитектура
JDBC — Java Database Connectivity — архитектура
Как следует из рисунка, приложение работает с абстракцией JDBC в виде набора интерфейсов. А вот
реализация для каждого типа СУБД используется своя. Эта реализация называется “JDBC-драйвер”. Для
каждого типа СУБД используется свой JDBC-драйвер — для Oracle свой, для MySQL — свой.
Система JDBC позволяет загрузить JDBC-драйвер для конкретной СУБД и единообразно использовать
компоненты этого драйвера за счет того, что мы к этим компонентам обращаемся не напрямую, а через
интерфейсы.
Т.е. приложение в принципе не различает, обращается оно к Oracle или PostgreSQL — все обращения
идут через стандартные интерфейсы, за которыми “прячется” реализация.
Несколько важных интерфейсов
1. java.sql.DriverManager
2. java.sql.Driver
3. java.sql.Connection
4. java.sql.Statement
5. java.sql.PreparedStatement
6. java.sql.CallableStatement
7. java.sql.ResultSet
JDBC — Java Database Connectivity — архитектура

Как и все Java API, JDBC является набором классов и интерфейсов, в


совокупности поддерживающих определенный набор функций. В случае
JDBC эти функции обеспечивают доступ к базе данных. Классы и
интерфейсы, составляющие JDBC API, являются, таким образом,
абстракциями понятий, общих при доступе к базам данных любого типа.
Например, Connection является интерфейсом Java, представляющим
соединение с базой данных. Аналогично ResultSet представляет
результирующий набор данных, возвращаемый командой SQL SELECT.
Классы, образующие JDBC API, находятся в пакете Java, sql, который был
введен Sun в JDK 1.1.
JDBC — Java Database Connectivity — архитектура

Естественно, что конкретные детали доступа к базе данных зависят от ее


изготовителя. JDBC фактически не имеет дела с этими деталями. Большая
часть классов в пакете Java.sql является интерфейсами без реализации.
Реализация этих интерфейсов осуществляется производителем базы
данных в виде драйвера JDBC. В качестве программиста баз данных вам
нужно знать очень немногое относительно драйвера, который вы
используете, — все остальное делается через интерфейсы JDBC.
Специфическая информация о базе данных, которая необходима для
использования JDBC, включает в себя:
• URL для драйвера JDBC.
• Имя класса, реализующего Java. sql. Driver.
JDBC — Java Database Connectivity — архитектура

Оба эти элемента можно получить во время выполнения - из командной


строки или файла свойств. Сам код программы не ссылается на эти два
зависящие от реализации элемента. Мы разъясним, что делают JDBC URL
и класс Driver в тех параграфах, где будем рассказывать о соединении с
базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов


Java) API. Он позволяет запоминать объекты Java в службе имен и
каталогов, такой как сервер Lightweight Directory Access Protocol
(облегченный протокол доступа к каталогам - LDAP), и находить их по
имени.
Соединение с базой данных

Прежде всего нужно соединиться с базой данных. Один из немногих


реализованных в пакете Java. sql. package классов - это класс
DriverManager. Он поддерживает список реализаций JDBC и обеспечивает
создание соединений с базами данных на основе сообщаемых ему JDBC
URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает
DriverManager, с какой СУБД нужно соединиться, и передает ему данные,
необходимые для осуществления соединения.
Соединение с базой данных

Часть URL, обозначающая протокол, ссылается на конкретный драйвер


JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql
соответственно. Субпротокол сообщает данные соединения,
специфические для реализации. Для соединения с MySQL и mSQL
требуются имя узла и имя базы данных. Дополнительно может
потребоваться номер порта, если ядро базы данных запущено не как root.
Поэтому полный URL для mSQL выглядит как, например,
jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о
необходимости найти драйвер JDBC для mSQL и соединиться с базой
данных test на athens.imaginary.com через порт 1114. Это делается путем
единственного обращения к методу getConnection() интерфейса
DriverManager.
Соединение с базой данных

Часть URL, обозначающая протокол, ссылается на конкретный драйвер


JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql
соответственно. Субпротокол сообщает данные соединения,
специфические для реализации. Для соединения с MySQL и mSQL
требуются имя узла и имя базы данных. Дополнительно может
потребоваться номер порта, если ядро базы данных запущено не как root.
Поэтому полный URL для mSQL выглядит как, например,
jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о
необходимости найти драйвер JDBC для mSQL и соединиться с базой
данных test на athens.imaginary.com через порт 1114. Это делается путем
единственного обращения к методу getConnection() интерфейса
DriverManager.
Соединение с базой данных
import java.sql.*; 
public class Connect { public static void main(String argv[]) {
Connection con = null; 
try { 
// Вот JDBC URL для этой базы данных
 String url = "jdbc:msql://athens.imaginary.com:1114/db_test";
// 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;
 // передать это как свойство, т.е.
// -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver
// или загрузить, как сделано в этом примере
Class.fоrName("com.imaginary, sql. msql. MsqlDriver");
// здесь осуществляется соединение
con = DriverManager.getConnection(url, "borg", "");}
catch( SQLException e ) { 
e.printStackTrace(); } 
finally { 
if( con != null ) {
try { con.close();}
catch( Exception e ) { }}}}}
 
Соединение с базой данных
Возможные реализации 

jdbc:mysql://localhost:3306/Database_dbName?
allowPublicKeyRetrieval=true&useSSL=false;
 
То есть в нашем случе
con1=(Connection)DriverManager.getConnection("jdbc:mysql://localhost:3306/DateBase?
allowPublicKeyRetrieval=true?useSSL=false", "Admin","123");

Оценить