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

Язык программирования

Java
План
1. Введение в Java-технологии
2. Синтаксис языка Java
3. Массивы и строки
4. Объектно-ориентированное программирование
5. Исключения
6. Потоковый ввод-вывод
7. Коллекции
8. Графический пользовательский интерфейс
9. События
10.Java2D
11.Потоки исполнения

Введение в Java-технологии

Хронология развития языка Java


1991
Проект “Oak” – программирование устройств бытовой электроники
1994
Браузер “WebRunner” – интерактивные апплеты для гипертекстовых страниц
1995
Официальное объявление технологии Java
1997
Первые применения Java для разработки корпоративных информационных
систем
...
Составляющие Java-технологии
Жизненный цикл Java-приложения
Особенности Java-технологии

1. Переносимость
Программы, написанные на языке Java, после однократной трансляции в
байт-код могут быть исполнены на любой платформе, для которой
реализована виртуальная Java-машина.
Особенности Java-технологии

2. Безопасность
Функционирование программы полностью определяется (и ограничивается)
виртуальной Java-машиной.

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


физической памятью и прочим аппаратным обеспечением компьютера.
Особенности Java-технологии

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

Присутствует строгий контроль типов,


обязательный контроль исключительных ситуаций.

Многие логические ошибки обнаруживаются на этапе компиляции.


Особенности Java-технологии

4. Сборщик мусора
Освобождение памяти при работе программы осуществляется автоматически
с помощью «сборщика мусора».

(программировать проще и надежнее)


Особенности Java-технологии

5. Самодокументируемый код
Имеется механизм автоматического генерирования документации на основе
комментариев, размещенных в тексте программ.
Особенности Java-технологии

6. Многообразие типов приложений


На языке Java возможно реализовать абсолютно разные по способу
функционированию и сфере использования программы.
Типы Java-приложений

1. Приложения (application)
обычные прикладные программы, которые запускаются пользователем и
имеют доступ ко всем ресурсам компьютера наравне с любыми другими
программами.
Типы Java-приложений
2. Мидлеты (midlet)
специализированные программы, предназначенные для использования на
мобильных устройствах. Структура и возможности мидлетов обусловлены
техническими особенностями мобильных устройств.
Типы Java-приложений

3. Апплеты (applet)
специализированные программы, обычно небольшого размера, запускаемые
браузером внутри web-документа для вывода динамического содержимого
и/или интерактивного взаимодействия с пользователем.
Типы Java-приложений

4. JSP-страницы (Java Server Pages)


HTML-документы со вставками на языке Java, используемые web-серверами
для анализа пользовательских запросов и динамического формирования web-
документов на основе результатов обработки этих запросов.
Типы Java-приложений

5. Сервлеты (servlet)
специализированные программы, функционирующие в рамках web-сервера и
имеющие доступ к его ресурсам: файлам, базам данных и т.п.

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


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

При реализации примитивных типов объектно-ориентированный


подход не используется.

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


Синтаксис языка Java
Язык Java имеет строгую типизацию, т.е. все переменные, константы,
выражения имеют свой тип, который должен быть определен еще на этапе
трансляции программ.
Тип данных определяет
–набор значений, которые может иметь переменная или которые могут
получаться в результате вычисления выражения;
–набор операций, применимый к этим значениям;
–смысл этих операций.
Типы данных языка Java
Логический тип данных (boolean) используется для представления двух
логических значений: «истина» или «ложно».

Символьный тип данных (char) используется для представления кодов


символов в двухбайтовой кодировке Unicode.

Целочисленные типы данных отличаются диапазонами допустимых


значений:

byte -27 27 – 1
short -215 215 – 1
int -231 231 – 1
long -263 263 – 1
Все целочисленные типы знаковые.
Вещественные типы данных отличаются точностью представления
значений:

float – одинарная точность (7-8 цифр)


double – двойная точность (17 цифр)

Константы

Константами обычно называют представление значений типов


данных в тексте программы.

Логические константы записываются с помощью ключевых слов

true – «истина»

false – «ложь»
Целочисленные константы могут быть записаны в трех системах
счисления:

–десятичной (1, 10, 100);


–восьмеричной (01, 010, 0100);
–шестнадцатеричной (0x1, 0x10, 0x100).
По умолчанию целочисленным константам сопоставляется тип int.
При необходимости использовать константы типа long, следует
указывать суффикс типа данных ‘L’.

Например:
2147483648L
0xABCDEFL
Вещественные константы могут быть записаны в десятичной или
шестнадцатеричной системах счисления.
Признаком десятичной вещественной константы служит:
–десятичный разделитель ‘.’;
–экспоненциальная часть, начинающаяся с ‘E’;
–суффикс типа данных – ‘F’ (float) или ‘D’ (double).

Если суффикс типа данных явно не указан, то используется тип double.


При записи вещественной константы в шестнадцатеричной системе
счисления обязательно должна присутствовать экспоненциальная часть,
начинающаяся с ‘P’, которая указывает на степень двойки.

Например:
0x3P-5 → 3 ∙ 2-5
0xB.8P10 → 11.5 ∙ 210.
Символьные константы представляют собой отдельные символы,
записанные в одиночных кавычках (апострофах).

Значением символьной константы является целое число от 0 до 65535 –


код символа в кодировке Unicode.
Непечатные и специальные символы могут быть представлены с
помощью:

–escape-последовательностей, например, '\n'


(допускаются значения '\\', '\'', '\"', '\b', '\f', '\n', '\r', '\t');
–кода символа, записанного в восьмеричной системе счисления,
например, '\100'
(допускаются значения от \000 до \377);
–кода символа, записанного в шестнадцатеричной системе счисления,
например, '\u0020'
(допускаются значения от '\u0000' до '\uFFFF').
Строковые константы записываются в двойных кавычках и могут
содержать как печатные символы, так и символы, задаваемые escape-
последовательностями или с помощью кода.
Внутреннее представление строк использует кодировку Unicode и не
зависит от программно-аппаратной платформы.
Особенностью строковых констант является то, что они являются
записью значений ссылочного типа данных String, т.е. фактически
представляют собой ссылки на автоматически создаваемые объекты этого
типа.
Специальная константа – пустая ссылка null – совместима с
переменными любого ссылочного типа и обозначает отсутствие ссылки на
объект.
Операторы

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


символов, используемую для обозначения операции, которая выполняется
над данными.
Арифметические операторы применяются к значениям числовых типов
данных (в том числе и char).

–операторы инкремента ++ и декремента – –;


–аддитивные операторы + и –;
–мультипликативные операторы *, / и %;
–побитовые операторы ~ («не»), & («и»),
| («или»), ^ («исключающее или»);
–операторы битового сдвига <<, >>, >>>.
Особенности выполнения операций:

/,%
действие зависит от типа операндов

>>
знаковый сдвиг

>>>
беззнаковый сдвиг
Операторы отношения <, >, = =, <=, >=, != позволяют сравнивать
значения двух совместимых между собой примитивных типов данных.

Операторы отношения = = и != могут применяться к значениям ссылочных


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

–оператор отрицания !;
–операторы полных логических операций
& («и»), | («или»), ^ («исключающее или»);
–операторы сокращенных логических операций
&& («и»), || («или»).

Результатом логических операций является значение логического типа.


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

Например:
(x==y) || (x==–y)
(n!=0) && (m/n>0)
Условный оператор ? : позволяет вычислить значение одного из двух
выражений в зависимости от истинности некоторого условия.

Например: a>b ? a : b
Операторы присваивания позволяют менять значение переменных.

Оператор простого присваивания применяется к переменным любого


типа:
a = b;

Операторы составного присваивания позволяют изменить значение


числовой переменной, выполнив над ней одну из 11 бинарных
арифметических операций
a += b;
Переменные

Переменной называют программный объект (не в смысле ООП),


имеющий имя и значение, которое может быть получено и изменено
программой.
Синтаксис объявления переменных
[ final ] тип имя [ = значение ]
В зависимости от места объявления переменных различают:

–формальные параметры – объявляются в заголовке метода;

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


метода;

(глобальные переменные в языке Java отсутствуют!)


Область видимости переменной
простирается от места объявления переменной до конца блока, в котором
была объявлена переменная

{
// . . .
int x;
// . . . область
// . . . видимости
// . . . переменной
}
В языке Java не разрешается повторно использовать имена переменных
внутри вложенных блоков:

{
// . . .
int x;
// . . .
{
// . . .
double x; // ошибка!
// . . .
}
// . . .
}
Если при объявлении переменной был использован модификатор final,
то значение такой переменной изменить нельзя.

final int x;
// . . .
x=18; // ошибка!
До первого использования переменным должно быть присвоено
значение.

Переменным с модификатором final значение должно быть присвоено


при объявлении.

int x;
x=5;

final int y=6;


Выражения

Выражениями обычно называют конструкцию языка


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

–по приоритету операций:


b*b – 4*a*c
–с помощью скобок:
b*(b – 4)*a*c
–по ассоциативности операций
a+b+c
a=b=c
–по форме записи (префиксная или постфиксная):
a – b++
a – ++b
Приоритеты операций (от старшего к младшему):

–операции инкремента и декремента;


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

1. Операнды типа byte, short, char перед выполнением операции


всегда приводятся к типу int.

byte a=10;
byte b=20;
int c=a+b;
2. Если в одной операции смешиваются операнды разных типов, то
тип операнда с меньшей точностью приводится к типу операнда с большей
точностью:

int ® long
int, long ® float
int, long, float ® double

3. При присваивании тип значения справа приводится к типу


переменной слева (если при этом не происходит потери точности):

double c = 16 / 5;

но
int a = 15.0 / 3.0; // ошибка
В выражениях можно использовать явное преобразование типа
операндов:

byte a=10;
byte b=20;
byte c=(byte)(a+b);

int Summa, Kolichestvo;


...
double Srednee=(double)Summa/Kolichestvo;

int c=(int)(15.0/3.0);
Математические функции и константы

В языке Java математические функции (37 шт.) и константы (2 шт.)


доступны посредством объекта Math.
Math.E – число e
Math.PI – число p

Большинство функций соответствуют языку C, например:


Math.abs(x) – модуль числа
Math.sqrt(x) – квадратный корень из числа
и т.д.
Имеются функции для часто выполняемых операций, например:

Math.min(x,y) – минимум из двух чисел


Math.max(x,y) – максимум из двух чисел

Math.hypot(x,y) – гипотенуза прямоугольного


треугольника с катетами {x,y}

Math.toRadians(x) – преобразовать из градусов


в радианы

Math.toDegrees(x) – преобразовать из радианов


в градусы
Структура простейшего Java-приложения

public class HelloWorld {

public static void main(String arg[]) {


System.out.println("Hello, World!");
}

}
Структурные операторы

Язык программирования Java имеет полный набор структурных


операторов.
Составной оператор { }

Составной оператор предназначен для логического объединения


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

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


видимости переменных.
Оператор ветвления

–краткая форма записи


if (условие) оператор;
–полная форма записи
if (условие) оператор1; else operator2;

В качестве условия должно выступать логическое (boolean) выражение.

В качестве операторов могут быть использованы составные


операторы.
В соответствии с «Code Conventions for the Java Programming Language»
рекомендуется оформлять операторы ветвления следующим образом:

if (условие) {
операторы1;
} else {
операторы2;
}
Оператор цикла с предусловием

while (условие) оператор;

или
while (условие) {
операторы;
}
Оператор цикла с постусловием

do оператор; while (условие);

или
do {
операторы;
} while (условие);
Оператор цикла с параметром

for(список1;условие;список2) оператор;

или
for(список1;условие;список2) {
операторы;
}
Операторы управления итерациями

–оператор прекращения цикла


break;

–оператор перехода к следующей итерации


continue;
Оператор выбора

switch (выражение) {
case константа1: оператор1;
case константа2: оператор2;
case константа3: оператор3;
...
default: оператор;
}

Выражение может иметь любой целочисленный тип, кроме long (byte,


short, int, char)
Константы в операторе выбора играют роль меток, т.е. указывают на
точки входа. У одной точки входа может быть несколько меток-констант.

switch (выражение) {
case константа1:
case константа2:
case константа3: оператор;
После входа выполняются операторы до конца всей конструкции.

Для выхода из конструкции следует использовать break.

switch (выражение) {
case константа1: оператор1; break;
case константа2: оператор2; break;
case константа3: оператор3; break;

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

–объявление массивов;
–создание массивов;

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


массивов.
Объявление массивов

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


видов:

тип имя[];
или
тип[] имя;

При объявлении массива создается лишь ссылочная переменная.


При объявлении одного массива обе записи эквивалентны.

Различия проявляются при объявлении нескольких переменных:

int a[],b,c; – массив и две переменных


или
int[] a,b,c; – три массива

Создание массивов

Массивы создаются в динамически распределяемой памяти по команде


вида:
new тип [размер];

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


объекту, например:
a=new int[25];

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


Инициализация массивов

Инициализация массива (т.е. присваивание начальных значений) может


выполняться как при объявлении:
тип имя[] = {список значений};
так и при создании массива:
имя=new тип[] {список значений};

В обоих случаях размер массива определяется в соответствии с


количеством инициализационных значений.
Индексы элементов массива начинаются с 0.

Для определения количества элементов в массиве можно использовать


поле length.

Типичная циклическая конструкция по обработке элементов массива:

S=0;
for(int i=0;i<A.length;i++) {
S+=A[i];
}
Для обработки всех элементов массива может использоваться
специальная форма записи цикла for, не содержащая в явном виде параметра
цикла:
for(тип имя : массив) {
операторы;
}

Например:
S=0;
for(double element : A) {
S+=element;
}
Операции над массивами
–присваивание: a=b;
при присваивании копируется ссылка, т.е. обе переменных будут ссылаться
на один и тот же массив;

–сравнение: a==b или a!=b


сравниваются ссылки на массивы, т.е. два массива равны, если это один и тот
же массив;

–освобождение ссылки: a=null;


если на массив отсутствуют другие ссылки,
то он (когда-нибудь) уничтожается
Двумерные (многомерные) массивы

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


синтаксис:
тип имя[][];
или
тип[][] имя;

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


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

// объявление двумерного массива


int mas2D[][];

// создание прямоугольного массива


mas2D=new int [N] [M];

// создание треугольного массива


mas2D=new int [N] [];
for(int i=0;i<N;i++)
mas2D[i]=new int[i+1];
При инициализации двумерных массивов необходимо сгруппировать
элементы, образующие отдельные строки:

mas2D = new int [] [] { {1}, {2,3}, {4,5,6} };


Для обработки двумерных массивов можно использовать как
традиционный цикл for, так и его модифицированный вариант.
Пример 1. Сумма элементов двумерного массива

S=0;
for ( int i=0 ; i<mas2D.length ; i++ )
for ( int j=0 ; j<mas2D[i].length ; j++ )
S+=mas2D[i][j];

Пример 2. Вывод двумерного массива

for ( int[] mas1D : mas2D ) {


for ( int element : mas1D )
System.out.print(element+" ");
System.out.println();
}
Строки

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


тип String.

Любые строковые константы, встречающиеся в тексте программы,


фактически рассматриваются как ссылки на объекты этого класса.

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


любые методы класса String.
Для внутреннего представления строк используется двухбайтовая
кодировка Unicode.
Это обеспечивает переносимость программ.
Все объекты-строки являются неизменяемыми, т.е. у строк отсутствуют
методы, позволяющие модифицировать их внутреннее представление.

Для того, чтобы изменить строку, необходимо создать новый объект с


требуемым содержимым.
Основные методы класса String

int length()
получение длины строки:
int n = str.length();
char charAt(int индекс)
получение одного символа из указанной позиции:
char c = str.charAt(i);

String substring(int индексОт, int индексДо)


получение копии части строки:
String str2 = str.substring(i,i+k);
Пример. Подсчет частоты вхождения символа в строку

String str="обороноспособность";
char c='о';

int n=0;
for(int i=0;i<str.length();i++)
if ( c==str.charAt(i) ) n++;
boolean equals(String строка)
сравнение строк
if ( str1==str2 )
if ( str1.equals(str2) )

int compareTo(String строка)


лексикографическое сравнение строк
if ( str1<str2 )
if ( str1.compareTo(str2)<0 )

boolean equalsIgnoreCase(String строка)


сравнение строк без учета регистра

int compareToIgnoreCase(String строка)


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

if ("admin".equalsIgnoreCase(user)
&& "q1G#bas.8".equals(password) )
{
System.out.println("Добро пожаловать!");
}
else
{
System.out.println("Посторонним вход запрещен!");
}
boolean contains(String подстрока)
содержит ли строка заданную подстроку?

boolean startsWith(String подстрока)


начинается ли строка на заданную подстроку?

boolean endsWith(String подстрока)


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

String sex="неизвестный";
if ( prilag.endsWith("ый") || prilag.endsWith("ий") )
sex="мужской";
if ( prilag.endsWith("ая") || prilag.endsWith("яя") )
sex="женский";
if ( prilag.endsWith("ое") || prilag.endsWith("ее") )
sex="средний";

System.out.println("Прилагательное " + prilag


+ " имеет " + sex +" род");

int indexOf(Char символ)


int indexOf(Char символ, int индексОт)
определяет первую позицию заданного символа в строке

int indexOf(String подстрока)


int indexOf(String подстрока, int индексОт)
определяет первую позицию заданной подстроки в строке

Если символ или подстрока не найдены, методы возвращают число -1.


int lastIndexOf(Char символ)
int lastIndexOf(Char символ, int индексДо)
определяет последнюю позицию заданного символа в строке

int lastIndexOf(String подстрока)


int lastIndexOf(String подстрока, int индексДо)
определяет последнюю позицию заданной подстроки в строке

Если символ или подстрока не найдены, методы возвращают число -1.


Пример. Извлечение текста из скобок

nachalo=stroka.indexOf( '(' );
konec=stroka.indexOf( ')', nachalo );

String text=stroka.substring(nachalo+1,konec);

(Пример требуется дополнить необходимыми проверками!)


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

String toLowerCase()
возвращает копию строки в нижнем регистре

String toUpperCase()
возвращает копию строки в верхнем регистре

Часто требуется получить строковое представление для значений


примитивных типов. Для этого используются статические методы класса
String:

String String.valueOf (boolean b)


String String.valueOf (char c)
String String.valueOf (int i)
String String.valueOf (long l)
String String.valueOf (float f)
String String.valueOf (double d)
За обратное преобразование отвечают статические методы классов-
оболочек примитивных типов:

boolean Boolean.parseBoolean (String s)


byte Byte.parseByte (String s)
short Short.parseShort (String s)
int Integer.parseInt (String s)
long Long.parseLong (String s)
float Float.parseFloat (String s)
double Double.parseDouble (String s)
Если задано неверное представление величины, эти методы порождают
исключительную ситуацию.
Пример 1. Преобразование строки в число

int chislo = Integer.parseInt (stroka);

Пример 2. Преобразование числа в строку

String stroka = String.valueOf(chislo);

Класс StringBuilder

Класс StringBuilder также используется для представления объектов-


строк.

Некоторые методы класса StringBuilder совпадают с классом String:


length(), charAt(), indexOf() и т.д.

Класс StringBuilder имеет расширенную по сравнению с классом String


функциональность, поскольку объекты этого класса могут изменяться.

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


ссылку на этот же объект.

Благодаря этому можно использовать цепочки вызовов:

объект.метод1(…).метод2(…).метод3(…);

вместо

объект.метод1(…);
объект.метод2(…);
объект.метод3(…);
StringBuilder append(что)
используется для добавления к объекту других строк и строковых
представлений значений примитивных типов (13 вариантов)

StringBuilder sb=new StringBuilder();


sb.append("Число равно ").append(x);
Метод append() неявно используется при склеивании строк:

String s = "Число равно "+x;


ß
String s = new StringBuilder("Число равно ")
.append(x)
.toString();
StringBuilder insert(int индекс, что)
используется для вставки в строку других строк и строковых представлений
значений примитивных типов (12 вариантов)

StringBuilder sb=new StringBuilder( "(,)" );


sb.insert(2,y);
sb.insert(1,x);
delete(int индексОт,int индексДо)
используется для удаления части строки

StringBuilder sb=new StringBuilder( "корова" );


sb.delete(3,5);

replace(int индексОт,int индексДо,String подстрока)


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

StringBuilder sb=new StringBuilder( "корова" );


sb.replace(3,6,"ыто");

StringBuilder deleteCharAt(int индекс)


используется для удаления символа в указанной позиции

StringBuilder setCharAt(int индекс,char символ)


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

StringBuilder sb=new StringBuilder( "маруся" );


sb.setCharAt(0,'п');
sb.deleteCharAt(5);

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

Взаимодействие между объектами происходит путем передачи


сообщений.

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


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

Набор действий, который объект может выполнить, определяет


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

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


Синтаксис описания классов

[доступ] class ИмяКласса


[extends ИмяСуперКласса]
[implements СписокИнтерфейсов] {
// описание полей и методов класса
}
Синтаксис описания полей

[доступ] [модификаторы] ИмяТипа имяПоля = Значение;


Типы доступа

private
доступ разрешен только из методов данного класса
protected
доступ разрешен только из методов данного класса и его подклассов
public
доступ разрешен из методов любых классов

нет обозначения
доступ разрешен из методов классов из текущего пакета
Виды модификаторов

static
данное поле является общим для всех экземпляров класса (переменная
класса)

final
значение данного поля не может быть изменено

Комбинация этих двух модификаторов (final static) обычно


используется для описания констант.
Пример. Описание класса «Точка».

class Point {
double x;
double y;
}
В языке Java классы относятся к ссылочным типам данным. Это значит,
что все для работы с объектами простого описания полей или переменных
недостаточно.

Обязательно нужно создать объект:

имяПеременной = new ИмяТипа(параметры);


Например:
Point A;
A = new Point();
или
Point B = new Point();

Для уничтожения объекта достаточно освободить ссылку:


A = null;

Для доступа к полям и методам объекта используется оператор . (точка):

имяПеременной . имяПоля
или
имяПеременной . имяМетода (параметры)
Например:
A.x = 5;
A.y = 7;
Синтаксис описания методов

[доступ] [модификаторы]
ВозвращаемыйТип имяМетода ( [СписокПараметров] )
[throws СписокИсключений] {
// тело метода
}

В языке Java тело метода всегда записывается


внутри описания класса!
Типы доступа
те же самые, что и у полей

Виды модификаторов
static
действие метода не зависит от конкретного объекта (метод класса)
final
данный метод не может быть переопределен в подклассах
Для доступа к статическим полям и методам объекта (переменным
класса и методам класса) используется следующий синтаксис:

ИмяКласса . имяПоля
или
ИмяКласса . имяМетода (параметры)

Например:
Math.PI
String.valueOf(…)
Внутри метода для доступа полям и методам текущего объекта может
быть использован идентификатор this:
this . имяПоля
или
this . имяМетода (параметры)
Для возвращения значения из метода используется оператор return:
return выражение;
Если метод не должен возвращать значение, в заголовке метода вместо
возвращаемого типа должно указываться ключевое слово void.
Пример. Описание класса «Отрезок».

class Segment {
Point p1;
Point p2;

Point getMidpoint() {
Point p = new Point();
p.x = (p1.x+p2.x)/2;
p.y = (p1.y+p2.y)/2;
return p;
}
}
Инкапсуляция
Принцип инкапсуляции означает, что доступ извне к состоянию объекта
ограничивается или запрещается.

Взаимодействие с объектом должно осуществляться исключительно


(или почти исключительно) путем передачи сообщений (вызовов методов).
В языке Java для реализации принципа инкапсуляции используется
ограничение доступа в комбинации со специальными видами методов,
называемых getter'ами и setter'ами.
Типичные getter'ы и setter'ы выглядят так:

private Тип поле;

public Тип getПоле() {


return поле;
}

public void setПоле(Тип поле) {


this.поле=поле;
}
Пример. Getter'ы и setter'ы для класса «Точка».

public double getX() {


return x;
}
public void setX(double x) {
this.x=x;
}

public double getY() {


return y;
}
public void setY(double y) {
this.y=y;
}
Многие Java-технологии (технология разработки компонентов
JavaBeans, технологии объектно-реляционного отображения баз данных и
др.) в обязательном порядке требуют наличия getter'ов и setter'ов в
проектируемых классах.

Большинство интегрированных сред разработки Java-приложений


содержат возможность автоматической генерации getter'ов и setter'ов только
на основании описания полей
Конструкторы
Конструкторами называют специальные методы, основная задача которых –
подготовить начальное состояние объекта (выполнить инициализацию полей)

Общий вид конструктора:

public ИмяКласса ( [Список параметров] ) {


// тело конструктора
}

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


конструкторов, отличающихся своими параметрами.
Пример. Возможные конструкторы класса «Точка».

public Point() {
x=0;
y=0;
}

public Point(double x, double y) {


this.x = x;
this.y = y;
}
Большинство интегрированных сред разработки Java-приложений
содержат возможность автоматической генерации конструкторов на
основании описания полей
При написании конструкторов допускается в первой команде с помощью
ключевого слова this записывать вызов другого конструктора этого же
класса:

public Point() {
x=0;
y=0;
}
ß

public Point() {
this(0,0);
}
Пример. Реализация метода getMidpoint с использованием getter'ов и
конструктора

public Point getMidpoint() {


return new Point( ( p1.getX()+p2.getX() )/2,
( p1.getY()+p2.getY() )/2 );
}
Наследование
Принцип наследования означает возможность формировать новые
классы на основе ранее описанных.

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


методами.

Принцип наследования позволяет поэтапно строить классы от простого


к сложному.

Для реализации наследования в языке Java используется ключевое слово


extends ("расширяет"):

class НовыйКласс extends СтарыйКласс {


// описание новых полей и методов
}
Пример. Иерархия классов, описывающая пользователей

public class User {


private String login;
private String password;
// …
}

public class Student extends User {


private String group;
// …
}

public class Teacher extends User {


private String chair;
// …
}
Принято исходный (базовый, родительский) класс называть
суперклассом, вновь созданный класс (производный, дочерний) –
подклассом.

Открытые (public) и защищенные (protected) поля и методы


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

По умолчанию суперклассом любого класса является класс Object.

Класс Object содержит в своем составе 11 методов, например:

String toString()
получить текстовое представление объекта

boolean equals(Object obj)


проверить эквивалентность двух объектов

public int hashCode()


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

Кроме того, в первой команде каждого конструктора подкласса


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

class Point3D extends Point {

private double z;

public Point3D(double x, double y, double z) {


super(x,y);
this.z = z;
}
// ...
}
Единственная ситуация, в которой разрешается не записывать вызов
конструктора суперкласса – это если в суперклассе имеется конструктор без
параметров (конструктор по умолчанию).

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

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


использования ключевого слова extends (т.е. суперклассом является класс
Object).
Полиморфизм
Наследование тесно связано с еще одним принципом ООП –
полиморфизмом.

В соответствии с принципом полиморфизма вместо объекта


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

Принцип полиморфизма позволяет использовать в программе схожие


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

User u;
Student s = new Student("n2008999","12345","П22");
Teacher t = new Teacher("kuntsevich","***","ПМиМ");

u=s; // Ok!
u=t; // Ok!
s=u; // Ошибка!
t=u; // Ошибка!
Пример. Использование полиморфизма при вызове метода

Point3D p1 = new Point3D(x1,y1,z1);


Point3D p2 = new Point3D(x2,y2,z2);

// вызов конструктора: Segment(Point p1,Point p2);


Segment s = new Segment(p1,p2);

Абстрактные классы

При построении иерархий классов часто нет необходимости (а иногда и


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

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


содержат абстрактные методы (методы, которые объявлены, но не
реализованы).

Каждый абстрактный метод должен быть перегружен в подклассе.


При описании абстрактного класса сам класс и требуемые методы
помечаются ключевым словом abstract:

abstract class ИмяКласса {


abstract Тип имяМетода( [список параметров] );
// ...
}

Тело у абстрактного метода отсутствует!

Объекты абстрактных классов создавать нельзя, но можно создавать


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

abstract class Figure {


abstract double getArea();
}

class Rectangle extends Figure {


private double a,b;
double getArea() {
return a*b;
}
// ...
}
Интерфейсы

Дальнейшим обобщением абстрактных классов являются интерфейсы


– ссылочные типы данных, содержащие только абстрактные методы и поля-
константы.
Объявление интерфейса

[public] interface ИмяИнтерфейса


[extends СписокИнтерфейсов]
{
// объявление полей интерфейса
// объявление методов интерфейса
}

При объявлении интерфейса все методы автоматически


рассматриваются как абстрактные, а все поля – как константы. Все элементы
интерфейса по умолчанию имеют область видимости public.
Примеры. Интерфейсы для геометрических фигур

public interface PointInterface {


double getX();
double getY();
}

public interface AreaInterface {


double getArea();
}
При объявлении классов список интерфейсов указывается после
ключевого слова implements ("реализует"):

class ИмяКласса implements СписокИнтерфейсов {


// ...
}
Пример. Класс "Точка"

public class Point implements PointInterface {


private double x;
private double y;

public double getX() {


return x;
}

public double getY() {


return y;
}

}
Пример. Класс "Окружность"

public class Circle extends Point


implements AreaInterface {

private double r;

public double getArea() {


return Math.PI*r*r;
}

}
Различия между классами и интерфейсами

1. Нельзя создать объект типа "интерфейс" (но можно переменной


типа "интерфейс" присваивать ссылку на объект любого класса,
реализующего этот интерфейс)

PointInterface p1 = new Point(x,y);


PointInterface p2 = new Circle(x,y,r);

2. В интерфейсах не может быть конструкторов (они могут быть


только в классах)
3. Элементы интерфейса всегда имеют область видимости public
(другие модификаторы указывать запрещается)

4. Интерфейс может расширять сразу несколько предков-


интерфейсов (класс может расширять только один класс)

5. Реализация методов интерфейсов может присутствовать только в


классах (интерфейсы всегда остаются абстрактными)
Пакеты
Каждое Java-приложение в своем составе может содержать десятки и
даже сотни классов.

В сложных проектах возможно дублирование имен классов, например:


Table – класс, описывающий таблицу
или
Table – класс, описывающий мебель (стол)

Также возможно совпадение имени пользовательского класса с именем


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

Пакеты имеют иерархическую структуру, соответствующую структуре


каталогов, и являются аналогами пространств имен (namespace) в языке C++.

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


полное (уточненное) имя, отличающее его от других одноименных классов.
Для указания принадлежности класса (классов) к какому-либо пакету
используется директива package:

package имя.пакета;

public class ИмяКласса {


// ...
}

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


проекта соответствовало именам пакетов, указанным в директивах package.
Полное (уточненное) имя класса состоит из имени пакета и имени
класса, например:
java.io.File
класс, описывающий файл, из пакета java.io
java.util.Date
класс, описывающий дату, из пакета java.util
java.sql.Date
класс, описывающий дату, из пакета java.sql
java.awt.Point
класс, описывающий точку, из пакета java.awt

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

// создание файла
java.io.File file;
file = new java.io.File("s:/myfile.txt");

// создание текущей даты


java.util.Date date;
date = new java.util.Date();

// создание точки
java.awt.Point point;
point = new java.awt.Point(x,y);
В качестве имени пакета компанией Sun рекомендуется использовать
доменное имя сайта, записанное в обратном порядке. Это гарантирует
уникальность имени пакета во всем мире, например:

com.sun.media.sound
пакет компании Sun для работы со звуком
org.w3c.dom.html
пакет организации World Wide Web Consortium для работы с языком HTML
org.netbeans.modules.image
пакет Netbeans для работы с изображениями
В некоторых случаях разрешается использовать краткие имена классов:

–для классов из пакета java.lang, например:


String или Integer
вместо вместо
java.lang.String java.lang.Integer
–для классов из текущего пакета
При необходимости использовать краткие имена для классов из других
пакетов, требуется их перечислить в директиве import:

import имя.пакета1.ИмяКласса1;
import имя.пакета2.ИмяКласса2;

или (не рекомендуется)

import имя.пакета.*;

Пример.

package my.labs.lab5;

import java.io.InputStream;
import java.io.BufferedReader;
import java.io.StringReader;
...
Исключения

Когда в ходе выполнения программы возникает ошибочная ситуация,


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

1. Невозможность нормального продолжения выполнения


программы, обнаруженная виртуальной машиной:
–попытка выполнить недопустимую арифметическую операцию
(например, попытка деления на 0);
–ошибка при загрузке программы или её части в память;
–нехватка аппаратных ресурсов (например, использование большого
количества памяти);
2. Исключение создано по инициативе программы.
3. Внутренняя ошибка виртуальной машины.
Исключения представляют собой специальные объекты, которые
содержат информацию о том, в каком месте программы и какая именно
ошибочная ситуация произошла:

–стек исполнения (показывает вложенность вызовов методов);


–текстовая строка, описывающая ошибку;
–возможно, ссылку на связанное исключение.

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


оператор try … catch … finally:

try {
// ... операторы, при выполнении которых возможна ИС
}
catch (ТипИС переменная) {
// ... обработка ИС
}
// ...
finally {
// ... блок освобождения ресурсов
}
Блок try
содержит команды, при выполнении которых возможно возникновение
исключений
Блок catch
содержит команды, выполняемые при возникновении того или иного типа
исключений
Блок finally
содержит команды, выполняемые независимо от наличия исключения

При возникновении исключения, оно передается для обработки


ближайшему подходящему по типу блоку catch.

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


выше и т.д.

Если в программе отсутствует подходящий обработчик, то исключение


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

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


позволяют автоматически сгенерировать подходящую конструкцию try …
catch.
Все исключения представляют собой экземпляры класса java.lang.Throwable
или его подклассов.

Эти классы принято называть классами исключений.

Стандартная библиотека классов Java содержит более 200 классов


исключений.
Основные методы класса Throwable

void printStackTrace()
выводит стек исполнения на экран
String getMessage()
возвращает текст сообщения об ошибке
String toString()
возвращает строку с описанием исключения (тип: сообщение)
Throwable getCause()
возвращает ссылку на связанное исключение
(если оно есть)
Базовая иерархия классов исключений

Throwable

Error Exception

VirtualMachineError RuntimeException

java.lang.Error
описывает серьезную проблему, с которой обычное приложение не может
справиться (например, LinkageError)
java.lang.VirtualMachineError
описывает ошибки, возникающие при работе виртуальной машины
(например, OutOfMemoryError, StackOverflowError)

java.lang.Exception
описывает исключения, возможность возникновения которых может быть
выявлена на этапе компиляции.
В большинстве случаев источник возникновения исключений расположен за
пределами приложения (например, IOException, PrinterException,
SQLException)

java.lang.RuntimeException
описывает исключения, источник возникновения которых расположен
внутри приложения (например, ArithmeticException,
IndexOutOfBoundsException, NullPointerException)
Если классы исключений, которые могут возникнуть при выполнении
фрагмента кода, находятся в родственной связи, то более конкретный класс
должен указываться раньше, более общий – позже, например:
try {
// ...
}
catch (ArithmeticException e) {
// ...
}
catch (RuntimeException e) {
// ...
}
catch (Exception e) {
// ...
}
Методы, которые по каким-то причинам не могут или не должны
обрабатывать генерируемые внутри них исключения, требуется помечать с
помощью ключевого слова throws:

Тип имяМетода (параметры) throws СписокИсключений {


// тело метода
}

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


возлагается на вызывающий метод.
Пример. Объявление метода для копирования файлов

void copyFile(String fileFrom,String fileTo)


throws IOException {
// ...
}
Если внутри метода может возникать, но не обрабатывается исключение типа
RuntimeException или любого его потомка, указывать throws нет
необходимости.
При перегрузке методов в классах-потомках, требуется, чтобы список throws
не содержал новых исключений по сравнению с классом-предком.

(Поскольку объекты классов-потомков могут использоваться вместо


объектов классов-предков, это может привести к необработанным
исключениям).
Для генерации исключения используется оператор throw:

throw new ТипИсключения(параметры);


Пример. Определение семейного состояния

boolean isMarried(String state)


throws IllegalArgumentException {

if ("женат".equalsIgnoreCase(state) ||
"замужем".equalsIgnoreCase(state) )
return true;

if ("неженат".equalsIgnoreCase(state) ||
"незамужем".equalsIgnoreCase(state) )
return false;

throw new IllegalArgumentException


("Неверно указано семейное состояние");

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

Пример.
class IllegalFamilyStatusException
extends IllegalArgumentException {
public IllegalFamilyStatusException() {
super("Неверно указано семейное состояние");
}
}

Потоковый ввод-вывод
В языке Java используется потоковая модель организации ввода-вывода.

Байт Байт Байт Байт Байт Программа


П о т о к

Это означает, что любая информация извне поступает в программу


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

Почти все они являются потомками четырех абстрактных классов,


размещенных в пакете java.io.

В абстрактных классах объявлена минимальная функциональность:


ввод (вывод) одного байта (символа) или массива байтов (символов).
Базовые классы потоков ввода-вывода
Ввод Вывод

Байтовый InputStream OutputStream

Символьный Reader Writer

Некоторые потомки базовых классов ввода-вывода


FileXXX
классы для организации файлового ввода-вывода
BufferedXXX
классы для буферизации ввода-вывода
DataXXX
классы для ввода-вывода примитивных типов
ByteArrayXXX, CharArrayXXX
классы для организации ввода-вывода из массивов байт (символов)
StringXXX
классы для организации ввода-вывода из строк
ObjectXXX
классы для ввода-вывода объектов
Основные методы класса InputStream
int read()
возвращает значение очередного байта, прочитанного из потока.
int read(byte[] b)
заполняет массив байтами, прочитанными из потока. Возвращаемое
значение равно количеству прочитанных байтов.
int read(byte[] b, int offset, int length)
начиная с индекса offset заполняет length элементов массива байтами,
прочитанными из потока.

При попытке чтения после конца потока


все методы возвращают значение –1.
Основные методы класса Reader
int read()
возвращает значение очередного символа, прочитанного из потока.
int read(char[] c)
заполняет массив символами, прочитанными из потока. Возвращаемое
значение равно количеству прочитанных символов.
int read(char[] c, int offset, int length)
начиная с индекса offset заполняет length элементов массива символами,
прочитанными из потока.

При попытке чтения после конца потока


все методы возвращают значение –1.
Основные методы класса OutputStream
void write(int b)
записывает один байт в поток.
void write(byte[] b)
записывает все элементы массива в поток.
void write(byte[] b, int offset, int length)
записывает в поток length элементов массива, начиная с индекса offset.
Основные методы класса Writer
void write(int b)
записывает один символ в поток.
void write(char[] c)
записывает все элементы массива в поток.
void write(char[] c, int offset, int length)
записывает в поток length элементов массива, начиная с индекса offset.

void write(String str)


записывает содержимое строки в поток
void write(String str, int offset, int length)
записывает в поток length символов строки,
начиная с индекса offset.
Типичная последовательность организации потокового ввода-вывода

1. создать объект-поток, указав необходимые параметры конструктора;

2. выполнить требуемые операции ввода-вывода, не забывая при этом


обрабатывать исключительные ситуации типа IOException;

3. закрыть поток методом close().


Файловый ввод-вывод

Классы FileInputStream, FileOutputStream,


FileReader, FileWriter
используются для создания потоков, связанных с файлами.

При создании объекта-потока в качестве параметра указывается строка


с именем файла, например:

FileInputStream fis = new FileInputStream("file.dat");


Пример. Копирование файла

FileInputStream fin=new FileInputStream("старый");


FileOutputStream fout=new FileOutputStream("новый");
byte bufer[]=new byte[4096];
int count;
do {
count=fin.read(bufer);
if (count>0) fout.write(bufer,0,count);
} while (count>0);

fin.close();
fout.close();
Буферизованный ввод-вывод

Классы BufferedInputStream, BufferedOutputStream,


BufferedReader, BufferedWriter
используются для повышения производительности при работе с другими
потоками.

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


существующий поток, например:
BufferedReader br =
new BufferedReader( new FileReader("file.dat") );
Дальнейшая работа с потоком осуществляется как обычно.
Бинарный ввод-вывод

Классы DataInputStream, DataOutputStream используются для ввода-


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

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


существующий байтовый поток, например:
DataInputStream dis =
new DataInputStream( new FileInputStream("file.dat") );
При работе с потоками используются методы:

для чтения для записи


boolean readBoolean() void writeBoolean(boolean v)
byte readByte() void writeByte(int v)
char readChar() void writeChar(int v)
double readDouble() void writeDouble(double v)
float readFloat() void writeFloat(float v)
int readInt() void writeInt(int v)
long readLong() void writeLong(long v)
short readShort() void writeShort(short v)
Пример. Запись переменных в поток
DataOutputStream dos = new DataOutputStream(...);
dos.writeBoolean(b); // логическая
dos.writeDouble(d); // дробная
dos.writeInt(i); // целая
dos.close();

Пример. Чтение переменных из потока


DataInputStream dis = new DataInputStream(...);
b=dis.readBoolean(); // логическая
d=dis.readDouble(); // дробная
i=dis.readInt(); // целая
dis.close();
Ввод-вывод объектов

Классы ObjectInputStream, ObjectOutputStream используются для ввода-


вывода объектов из байтовых потоков.

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


существующий байтовый поток, например:
ObjectInputStream ois =
new ObjectInputStream( new FileInputStream("file.dat") );
При работе с потоками могут использоваться те же методы, что и у классов
DataInputStream, DataOutputStream, и два специальных метода:

Object readObject()
для чтения объекта из потока
void writeObject(Object obj)
для записи объекта в поток
Пример. Запись объекта (массива) в поток

ObjectOutputStream oos=new ObjectOutputStream(...);


int intmas[]=new int[]{1,2,3,4,5};
oos.writeObject(intmas);
oos.close();

Пример. Чтение объекта (массива) из потока


ObjectInputStream ois=new ObjectInputStream(...);
int intmas[]=(int []) ois.readObject();
ois.close();
Преобразователи потоков
Классы InputStreamReader, OutputStreamWriter осуществляют
преобразование байтового потока в символьный и наоборот.

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


существующий байтовый поток и кодировочная таблица, которая будет
использоваться при преобразовании, например:
Reader r = new InputStreamReader(in,"cp866");
Writer w = new OutputStreamWriter(out,"cp866");
Таким образом, с байтовыми потоками можно работать используя
инструментарий для обработки символьных потоков.
Форматированный ввод
Класс java.util.Scanner позволяет по текстовому представлению
значений примитивных типов получить их внутреннее (двоичное)
представление.

Методы вида hasNextXXX() позволяют определить наличие в потоке


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

Методы вида nextXXX() позволяют считать из потока значения


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

Scanner scanner=new Scanner(System.in);

System.out.println("Введите строку");
String s=scanner.nextLine();

System.out.println("Введите целое число");


int n=scanner.nextInt();

System.out.println("Введите дробное число");


double d=scanner.nextDouble();
Форматированный вывод
Классы PrintStream, PrintWriter позволяют получить текстовое
представление значений примитивных типов.

Методы вида print(...) выводят в поток значения примитивных типов.


Метод printf(…) работает аналогично одноименной функции языка С.
Пример. Форматированный вывод

System.out.println("Результаты расчетов:");
System.out.printf("x=%5.3f, y=%5.3f%n",x,y);

Коллекции
Простейшим средством для хранения и обработки нескольких однотипных
объектов являются массивы.

Массивы мало пригодны для реализации алгоритмов обработки, при


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

Совокупность данных средств принято называть Java Collections


Frameworks или просто коллекции.

Некоторые классы и интерфейсы


Java Collections Framework

Iterable

Collecti
on

List Queue Set

ArrayLis HashSe
Vector Deque TreeSet
t t

ArrayDe
Stack
que

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


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

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


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

ИмяКласса<Тип> переменная;

переменная = new ИмяКласса<Тип>(...);


Пример 1. Создание стека целых чисел
Stack<Integer> stack;
stack = new Stack<Integer>();

Пример 2. Создание списка студентов


List<Student> students;
students = new ArrayList<Student>();

Пример 3. Создание множества точек


Set<Point> points;
points = new HashSet<Point>();
Интерфейс Iterable
Классы, реализующие этот интерфейс, предоставляют возможность
последовательной обработки элементов коллекции с помощью цикла for :

for ( Тип объект : коллекция ) {


// обработка объекта
}
Пример. Вывод списка студентов на экран
for ( Student student : students ) {
System.out.println(student);
}

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


соответствовать порядку добавления элементов
Интерфейс Collection
Описывает общие методы по обработке элементов коллекции

int size()
возвращает количество элементов коллекции;
boolean isEmpty()
проверяет, содержит ли коллекция элементы
(возвращает значение true, если коллекция пуста);
boolean contains(Object o)
проверяет, принадлежит ли объект коллекции
(возвращает значение true, если объект уже содержится в коллекции);
boolean add(E e)
добавляет элемент в коллекцию;

boolean remove(Object o)
удаляет из коллекции заданный объект
(если, конечно, он содержится в коллекции);

Методы add и remove возвращают значение true, если в результате их


выполнения состав коллекции изменился.

void clear()
очищает коллекцию (удаляет из коллекции
все содержащиеся в ней объекты);
Интерфейс List
Описывает списки – коллекции с фиксированным порядком
размещения элементов.

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


числами от 0 до size()-1.

Методы интерфейса List позволяют обращаться к каждому элементу


списка по индексу.
E get(int index)
возвращает ссылку на элемент из указанной позиции;

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

В случае отсутствия объекта в списке методы


indexOf(), lastIndexOf() возвращают значение –1.
void add(int index, E element)
вставить объект в указанную позицию списка;
E remove(int index)
удаляет объект из списка;
E set(int index, E element)
заменяет объект с указанным индексом на новый.

Методы set(), remove() возвращают ссылку на удаленный/замененный


объект.
Самыми используемыми реализациями интерфейса List являются классы
ArrayList и Vector, которые можно использовать, например, как массивы с
переменным количеством элементов.
Класс Stack, интерфейсы Queue и Deque
Класс Stack (стек), интерфейсы Queue (очередь) и Deque (двухстороння
очередь) используются для описания списочных структур данных, которые
позволяют обращаться к элементам, расположенных на краях списка.

Подобные структуры данных используются для реализации широкого


круга алгоритмов.
Основные методы стека, очереди и дека
Стек Очередь Дек Описание метода
добавить элемент в
void push(E e) void addFirst(E e)
начало списка
E remove() E removeFirst() извлечь первый элемент
E pop()
E poll() E pollFirst() из списка
E peek() E getFirst() получить ссылку на
E peek()
E element() E peekFirst() первый элемент
добавить элемент в
void add(E e) void addLast(E e)
конец списка
E removeLast() извлечь последний
E pollLast() элемент из списка
E getLast() получить ссылку на
E peekLast() последний элемент
Интерфейс Set
Интерфейс Set описывает множества.

Особенностью множеств является то, что все элементы в них различны.

Для этого при добавлении объекта внутри метода add() выполняется


проверка, присутствует ли во множестве элемент с таким значением.
Для сравнения объектов используются методы equals() и hashCode().

Чтобы обработка объектов пользовательских классов внутри множеств


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

Многие интегрированные среды разработки приложений позволяют


генерировать эти методы автоматически на основе выбранных полей.
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Point other = (Point) obj;
if (this.x != other.x) {
return false;
}
if (this.y != other.y) {
return false;
}
return true;
}

@Override
public int hashCode() {
int hash = 5;
hash = 11 * hash + (int) (Double.doubleToLongBits(this.x) ^
(Double.doubleToLongBits(this.x) >>> 32));
hash = 11 * hash + (int) (Double.doubleToLongBits(this.y) ^
(Double.doubleToLongBits(this.y) >>> 32));
return hash;
}
Для выполнения операций над отдельными элементами множеств могут
использоваться методы

add()
для добавления элемента в множество;
contains()
для проверки принадлежности элемента множеству;
remove()
для удаления элемента из множества

и т.д.
Для выполнения операций над двумя множествами могут использоваться
методы

boolean addAll(Collection<E> c)
добавляет в множество все элементы указанной коллекции (объединение
множеств);
boolean removeAll(Collection<E> c)
удаляет из множестве те элементы, которые принадлежат указанной
коллекции (дополнение множеств);
boolean retainAll(Collection<E> c)
оставляет в множестве те элементы, которые принадлежат указанной
коллекции (пересечение множеств);

Графический пользовательский интерфейс


Основой для разработки графического пользовательского интерфейса в языке
Java является библиотека Abstract Window Toolkit (java.awt).

Классы данной библиотеки позволяют использовать средства


используемой операционной системы для создания и использования
элементов пользовательского интерфейса, поддерживают обработку
событий, работу с Буфером обмена, обеспечивают реализацию технологии
Drag’n’Drop и т.д.
Усовершенствованным и расширенным вариантом библиотеки AWT
является библиотека Swing (javax.swing).

Её составляющие позволяют реализовать настраиваемый


пользовательский интерфейс, полностью независимый от используемой
операционной системы.
Для большинства элементов пользовательского интерфейса существует два
варианта реализации: в библиотеке AWT и в библиотеке Swing.
Например, кнопки описываются классами java.awt.Button и
javax.swing.JButton, текстовые поля – java.awt.TextField и
javax.swing.JTextField и т.д.

Несмотря на то, что подобные классы не всегда связаны отношением


наследования, большинство их методов совпадают.
Кроме того, компоненты библиотеки Swing имеют дополнительную
функциональность.
Основными понятиями, используемыми при разработке пользовательского
интерфейса являются компонент и контейнер.

Компонентами обычно называют классы (или объекты), которые описывают


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

Контейнерами называют такие компоненты, которые способны в себе (или


на себе) содержать другие компоненты, в т.ч. и другие контейнеры.

Все компоненты, содержащиеся в (на) контейнере, образуют список и


отображаются в соответствии со своим расположением в этом списке.
Классом-прародителем всех компонентов является класс
java.awt.Component.

Основными методами данного класса являются:


– методы, определяющие размеры и положение компонента (setSize(),
setLocation(), setBounds() и др.);
– методы, отвечающие за внешний вид компонента (setBackground(),
setForeground(), setFont(), setCursor(), setVisible() и др.);
– методы, отвечающие за обработку событий (addKeyListener(),
addMouseListener() и др.)

Классом-прародителем всех контейнеров является класс java.awt.Container.


Основными методами данного класса являются:

Component add(Component comp)


добавить компонент в контейнер;
Component add(Component comp, int index)
добавить компонент в указанную позицию списка компонентов;
void remove(Component comp)
удалить указанный компонент из контейнера;
void remove(int index)
удалить компонент из указанной позиции списка компонентов;
void removeAll()
удалить все компоненты из контейнера.
Изменение размеров и/или положения компонентов внутри контейнера
осуществляет специальный объект – менеджер размещения. Задать менеджер
размещения для контейнера можно с помощью метода setLayout().

Различные менеджеры размещения используют для определения


позиции и/или размеров компонентов различные правила.

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


положение каждого компонента требуется задать методами setSize(),
setLocation() или setBounds().
Иерархия классов-контейнеров
Component

Container

Panel Applet Dialog Window Frame

JComponent JPanel JApplet JDialog JWindow JFrame

Panel (JPanel)
реализует простейший контейнер, который должен быть размещен внутри
другого, более «продвинутого» контейнера.

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


панелей). Для панелей и их подклассов по умолчанию используется
менеджер размещения FlowLayout.
Applet (JApplet)
используется для разработки приложений-апплетов, встраиваемых в Web-
страницы.
Window (JWindow)
окно – представляет собой простейший независимый контейнер. Основные
атрибуты окна (заголовок, границы, строка меню) по умолчанию отключены.

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


инструментов и т.п. Для окон и их подклассов по умолчанию используется
менеджер размещения BorderLayout.
Dialog (JDialog)
диалоговое окно – используется для организации взаимодействия с
пользователем. В диалоговом окне по умолчанию отображаются заголовок
окна и граница.
Frame (JFrame)
окно приложения – представляет собой окно, имеющее заголовок и границу.
Пример. Создание простого окна
// создать окно с заголовком
JFrame frame = new JFrame("Простое окно");
// задать его размеры
frame.setSize(320, 240);
// при нажатии кнопки «Закрыть» происходит выход из программы
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// отобразить окно на экране
frame.setVisible(true);
// создать текстовую надпись ...
JLabel label = new JLabel("Hello, world!", JLabel.CENTER);
// ... и разместить её в окне
frame.add(label);
frame.validate();
Компонент Label
представляет собой однострочную текстовую надпись.
Текст надписи задается при вызове конструктора или методом setText(String
text).
Выравнивание надписи относительно границ компонента может быть задано
в конструкторе или методом setAlignment(int alignment).

Компонент JLabel
дополнительно позволяет отображать пиктограмму, которая задается при
вызове конструктора или методом setIcon(Icon icon).
Компонент Button
представляет собой кнопку.
Надпись на кнопке задается при вызове конструктора или методом
setLabel(String Label).

Компонент JButton
дополнительно позволяет отображать на кнопке пиктограмму, которая
задается при вызове конструктора или методом setIcon(Icon icon).
Кроме того, методами setPressedIcon(), setRolloverIcon(), setDisabledIcon() и
др. можно задать пиктограммы, соответствующие различным состояниям
кнопки.
Компонент TextField
представляет собой однострочное текстовое поле, используемое для ввода
текстовой информации. Начальное содержимое поля задается при вызове
конструктора или методом setText(String text). Введенный пользователем
текст можно получить методом getText().

Компонент JTextField
дополнительно позволяет организовать взаимодействие с системным
Буфером обмена с помощью методов copy(), cut(), paste(), а также
поддерживает технологию Drag’n’Drop.
Менеджеры размещения

За размещение компонентов в контейнерах отвечают специальные


объекты – менеджеры размещения.

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


определения положения и/или размеров компонентов в контейнере.

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


setLayout().
Менеджер размещения FlowLayout
Размещает компоненты, добавляемые в контейнер, построчно: слева
направо, сверху вниз.

При изменении размеров контейнера происходит перераспределение


положения компонентов с сохранением их размеров.

okoshko.setLayout( new FlowLayout() );


Менеджер размещения BorderLayout
управляет размещением пяти компонентов:
один – в центре контейнера, и ещё по одному – у каждого края окна.

okoshko.setLayout( new BorderLayout() );


Менеджер размещения GridLayout
размещает добавляемые в контейнер компоненты в виде прямоугольной
таблицы

okoshko.setLayout( new GridLayout(4, 4, 5, 5) );


количество строк
количество столбцов
промежуток по горизонтали
промежуток по вертикали
Менеджер размещения BoxLayout
размещает все компоненты в одну строку или в один столбец

okoshko.setLayout( new BoxLayout(okoshko, BoxLayout.X_AXIS) );


okoshko.setLayout( new BoxLayout(okoshko, BoxLayout.Y_AXIS) );

События
Графический пользовательский интерфейс приложения относится к
системам, управляемым по событиям:
– при запуске программы создается пользовательский интерфейс;
– далее приложение ожидает наступления некоторого события,
связанного с пользовательским интерфейсом;
– при наступлении события программа выполняет необходимые
действия, а затем снова переходит в режим ожидания.
Событием в пользовательском интерфейсе считается
– непосредственное действие пользователя (щелчок или движение мыши,
нажатие клавиши),
– изменение состояния какого-либо компонента интерфейса (например,
изменение состояния кнопки-переключателя).
При обработке событий в библиотеке Java взаимодействуют три вида
объектов:

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

В соответствии с этим шаблоном объект-источник события


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

Источник событий Слушатель событий 2

Слушатель событий 3

Один и тот же объект может являться слушателем у нескольких источников


событий:
Источник событий 1

Источник событий 2 Слушатель событий

Источник событий 3

Для описания объектов-событий используются классы, являющиеся


потомками java.awt.AWTEvent.

Каждый класс, описывающий событие, содержит свои специфические


методы, позволяющие получить информацию о произошедшем событии.
AWTEv

ent

ActionE Component TextEve


...
vent Event nt

PaintEv InputEv Window


...
ent ent Event

KeyEve Mouse

nt Event
Некоторые методы класса MouseEvent

int getButton()
возвращает номер нажатой кнопки (0, 1, 2, 3)

int getClickCount()
возвращает количество нажатий кнопки мыши
Point getPoint()
возвращает позицию указателя мыши
Некоторые методы класса KeyEvent

char getKeyChar()
возвращает символ, соответствующий нажатой клавише

int getKeyCode()
возвращает код нажатой клавиши

boolean isShiftDown()
boolean isControlDown()
boolean isAltDown()
возвращают состояние клавиш регистра
Для обработки любого события необходимо:

1. Создать объект-слушатель событий.


Объект-слушатель событий должен иметь метод(ы) для обработки
требуемого типа событий.

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


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

Объекты-слушатели событий должны реализовывать интерфейсы вида


***Listener, соответствующие событиям, например:

ActionListener
интерфейс слушателя события-действия
KeyListener
интерфейс слушателя события клавиатуры
MouseListener
MouseMotionListener
MouseWheelListener
интерфейсы слушателей событий мыши

Все интерфейсы объявлены в пакете java.awt.event


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

void actionPerformed(ActionEvent e)
метод для обработки события-действия
void keyPressed(KeyEvent e)
void keyReleased(KeyEvent e)
void keyTyped(KeyEvent e)
методы для обработки событий клавиатуры
Пример. Описание обработчика события нажатия на кнопку

class MyButtonClick implements ActionListener {


public void actionPerformed(ActionEvent e) {
// ... обработка нажатия на кнопку ...
}
}
В том случае, когда нет необходимости обрабатывать все типы событий, за
основу можно взять классы ***Adapter, содержащие пустые обработчики
событий, например:

KeyAdapter
класс-обработчик событий клавиатуры
MouseAdapter
MouseMotionAdapter
классы-обработчики событий мыши

Все классы-адаптеры объявлены в пакете java.awt.event


Пример. Описание обработчика события мыши

class MyMouseClick extends MouseAdapter {


public void mouseClicked(MouseEvent e) {
// ... обработка клика ...
}
}
Для регистрации слушателей событий у объектов, которые могут быть
источниками событий, имеются методы вида add***Listener(), например:

void addActionListener(ActionListener l)
добавить слушателя события-действия
void addKeyListener(KeyListener l)
добавить слушателя события клавиатуры
void addMouseListener(MouseListener l)
void addMouseMotionListener(MouseMotionListener l)
void addMouseWheelListener(MouseWheelListener l)
добавить слушателя событий мыши
и др.
Пример. Регистрация обработчика нажатия на кнопку

MyButtonClick myButtonClick=new MyButtonClick();


Button.addActionListener(myButtonClick);

Если объект-обработчик событий должен иметь возможность


обратиться к полям другого объекта (окна), то можно
1. Использовать параметризованный конструктор, параметром
которого будет требуемый объект-окно
2. Использовать встроенный класс-обработчик (т.е. класс, объявленный
внутри другого класса)
Для удаления слушателя событий используются методы вида
remove***Listener(), например:

void removeActionListener(ActionListener l)
удалить слушателя события-действия

JavaСтандартная библиотека Java включает в себя набор классов,


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

Совокупность данных средств принято называть Java2D.


2D

Основой для создания графических приложений на языке Java является


абстрактный класс Graphics.

Методы данного класса позволяют осуществлять построение


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

Данные операции существенно зависят от используемой графической


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

Graphics gr = component.getGraphics();

Это позволяет выполнять графические построения на поверхности


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

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


заполненной фоновым цветом. Для прорисовки собственного содержимого
достаточно перегрузить метод paint().
public MyComponent extends Canvas {

// ... описание полей и методов ...

public void paint(Graphics gr) {


super.paint(gr);
// прорисовка собственного содержимого
}
}
Основные методы класса Graphics делятся на несколько групп:

– методы для построения линий draw***();


– методы для построения областей fill***();
– методы для изменения параметров set***().
Методы для построения линий

void drawLine(int x1, int y1, int x2, int y2)


построить отрезок;
void drawRect(int x, int y, int width, int height)
построить границу прямоугольника;
void drawOval(int x, int y, int width, int height)
построить границу эллипса;
void drawPolygon(int[ ] x, int[ ] y, int n)
построить границу n-угольника.

Все построения выполняются текущим цветом.


Методы для построения областей

void fillRect(int x, int y, int width, int height)


построить внутреннюю область прямоугольника;
void fillOval(int x, int y, int width, int height)
построить внутреннюю область эллипса;
void fillPolygon(int[ ] x, int[ ] y, int n)
построить внутреннюю область n-угольника;

Все построения выполняются текущим цветом.


Методы для изменения параметров

void setColor(Color color)


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

Пример. Синий прямоугольник с зеленой границей


gr.setColor(Color.BLUE);
gr.fillRect(x1,y1,x2,y2);
gr.setColor(Color.GREEN);
gr.drawRect(x1,y1,x2,y2);

Методы класса Graphics позволяют выполнять элементарные графические


построения.

Более широкими возможностями обладает класс Graphics2D:

– построение линий различных видов и стилей;


– заполнение областей текстурами и градиентами;
– выполнение преобразований координат при построении.
Выбор стиля линии – void setStroke(Stroke s)

Классы, описывающие линии, должны реализовать интерфейс Stroke.

Основным классом является BasicStroke.

При создании объектов этого класса можно задавать различную


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

Stroke stroke = new BasicStroke(2.5);


gr2d.setStroke(stroke);
Выбор стиля заливки – void setPaint(Paint p)

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


интерфейс Paint:

Color
обеспечивает одноцветную закраску замкнутой области;
TexturePaint
обеспечивает заполнение замкнутой области узором (текстурой);
GradientPaint
обеспечивает плавное изменение цвета вдоль некоторого направления
Пример. Построение красно-синего прямоугольника.

Paint paint = new GradientPaint(


x, y, Color.RED,
x+width, y, Color.BLUE);

gr2d.setPaint(paint);
gr2d.fillRectangle(x,y,width,height);
Преобразование координат –
void setTransform(AffineTransform at)

Класс AffineTransform и его потомки позволяют выполнять аффинное


преобразование координат: параллельный перенос, поворот, сдвиг,
масштабирование и т.д., а также их композицию.

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


методов класса Graphics2D:

void rotate(double theta)


выполнить поворот на theta радиан;
void scale(double sx, double sy)
выполнить масштабирование с коэффициентами sx, sy по оси Ох и Оу,
соответственно;
void shear(double shx, double shy)
выполнить сдвиг с коэффициентами shx, shy;
void translate(double tx, double ty)
выполнить параллельный перенос на вектор (tx, ty).
Пример. Вывод надписи под углом 60 градусов.

double alpha=Math.PI/3;
double cos=Math.cos(alpha);
double sin=Math.sin(alpha);
AffineTransform rotate =
new AffineTransform(cos,-sin,sin,cos,100,100);
gr2d.setTransform(rotate);
gr2d.drawString("Надпись под углом PI/3", 0, 0);
Потоки исполнения

Вам также может понравиться