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

П.Е.

Пустовойтов

ПРОГРАММИРОВАНИЕ НА JAVA 2

учебное пособие
по дисциплине

«Вычислительная техника и программирование»

для студентов
специальности 6.091200 - Видео-, аудио- и кинотехника

Утверждено
редакционно-издательским
советом университета,
протокол №___ от ________

Харьков НТУ «ХПИ» 2007

1
ББК хх.ххх
УДК ххх.ххх

Рецензенты: Л.Г. Раскин, доктор техн. наук, НТУ «ХПИ»


Н.Ф.Логвиненко, канд. техн. наук, ХГУВД

Пустовойтов П.Є. Програмування на JAVA 2: Навчальний посібник. –


Харків: НТУ «ХПІ», 2007. – 76 с.

Представлен первый раздел «Программирование на JAVA 2» дисциплины


«Вычислительная техника и программирование». Изложен учебно-теоретический материал,
описывающий основные понятия и принципы программирования в целом. Теоретический
материал сопровождается примерами программ на JAVA 2.
Предназначено для студентов специальности 6.091200 - Видео-,аудио- и кинотехника.

Представлено перший розділ «Програмування на JAVA 2» дисципліни «Обчислювальна


техніка та програмування». Викладено учбово-теоретичний матеріал, що описує основні поняття
й принципи програмування в цілому. Теоретичний матеріал супроводжується прикладами
програм на JAVA 2.
Призначено для студентів спеціальності 6.091200 - Відео-, аудіо- та кінотехніка.

Ил. 10. Табл. 10. Библиогр. 6 назв.

ISBN

© П.Е. Пустовойтов, 2007


©НТУ «ХПИ», 2007

2
Вступление
Дисциплина «вычислительная техника и программирование» построена
на изучении объектно-ориентированного языка программирования Java.
Если кратко, то Java - это один из языков программирования. Он
разработан компанией Sun и является платформо-независимым. Это означает,
что программа, написанная на Java, будет одинаково выполняться в любой
операционной системе (Windows, Linux, и др.). Это достигается путем того,
что, текст программы переводится с помощью компилятора не в родные для
процессора команды, а в коды виртуальной java-машины (JVM). Коды
виртуальной машины одинаковы на любой платформе, и именно поэтому
одна и та же программа и будет работать на разных платформах. Эти коды
называются байт-кодами. Сама же виртуальная машина, естественно, зависит
от платформы (виртуальная машина для Windows отличается от виртуальной
машины для других ОС). В процессе изучения курса будем разрабатывать
программы на Java для Windows, но это не означает, что они не будут
работать на других платформах (рис.1).

Код Двоичный Код Компилятор БайтКод интер-


программ файл программы Java Java претатор
ы windows windows
____ Windows
____ ____
____ Двоичный ____ ____
____ интер-
файл ____ ____ претатор
____ linux ____ ____
____ linux
Unix ____ ____
____ ____ ____
Двоичный интер-
файл претатор
OS/2 OS/2
OS/2

Рисунок 1 – Различие между программами, написанными на Java и


программами, написанными на других языках

Прежде чем приступать к написанию программ необходимо


ознакомиться с набором средств для разработки приложений.
JDK расшифровывается как Java Developer Kit. Это набор программ и
утилит, предназначенный для программирования на Java. В его состав входит
ряд утилит.

3
 компилятор javac. Переводит текст программы на Java в байт-коды
виртуальной машины. Для каждой операционной системы разработан
свой компилятор javac, но байт-коды они генерируют одинаковые, не
зависящие от операционной системы;
 интерпретатор java. С его помощью запускаются откомпилированные
в байт-коды программы. Он содержит в себе JVM (Виртуальную
машину Java);
 утилита appletviewer. С ее помощью можно запускать апплеты
(программы, разрабатываемые для внедрения в HTML страницы);
 утилита javadoc. Предназначена для создания документации.
Скачать JDK можно с сайта www.java.sun.com . JDK - это бесплатный
набор. Как следствие, пользователям чистого JDK приходится работать без
особого комфорта - тексты программ необходимо набирать в Блокноте или
аналогичном текстовом редакторе. Чтобы написать программу на Java,
необходим качественный редактор. В качестве редактора будем использовать
Borland Java Builder X.
Направления, по которым развивается java.
 написание приложений ЭВМ;
 Applet;
 Servlet;
 JSP, JavaBeans;
 приложения для мобильных телефонов и карманных компьютеров;

1. Первые шаги в программировании


1.1. Первая программа на Java

1. Создание проекта. Выбираем пункт меню File->new project. В поле


Name вводим название проекта «prg1» (рекомендуется обратить внимание на
большие и маленькие буквы). Нажимаем кнопку finish.
2. Создание класса в проекте. Пункт меню File->new, закладка General.
Выбираем пиктограмму class. В поле Class name вводим название класса
«FirstProg». Нажимаем кнопку OK.
После вышеперечисленных манипуляций средой JBuilderX, будет
автоматически сгенерирован следующий код программы.
package prg1;
/**
* <p>Title: </p>

4
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2005</p>
* <p>Company: </p>
* @author not attributable
* @version 1.0
*/
public class FirstProg {
public FirstProg() {
}
}
Исправим его до такого кода.
package prg1;
import java.lang.*;
public class FirstProg{
public static void main(String [] args){
System.out.println("Hello World!");
}
}
Здесь
package – название пакета в котором будет находиться
prg1;
разрабатываемый класс;
import java.lang.*; – подключение дополнительных классов и пакетов;
public – сообщаем, что класс является общедоступным;
class FirstProg{ – название класса. Далее от символа { до последнего
символа } будет находиться внутренний код класса – сама программа;
public static void main(String [] args){ – главный метод класса, называемый
еще и запускающим методом. Он всегда является общедоступным public и
статическим static. Тип выдаваемых данных метода - void, это значит, что этот
метод не выдает данных.
main – название метода. Между фигурными скобками, которые
ограничивают тело метода, собственно говоря, и будет находиться текст
первой программы.
System.out.println("Hello World!"); – в теле программы вызывается функция
вывода на консоль надписи
Hello World!
Во время первого запуска JBuilder предложит настроить RunTime
Configuration. В появившемся окне нажимаем кнопку new. В поле main class
указываем имя главного класса, в данном случае это – prg1.FistProg.
Сохраняем RunTime Configuration и запускаем заново программу.

5
1.2. Переменные и типы данных

Переменная – ячейка в памяти, которая может принимать и хранить


какое-нибудь значение (цифра, буква, набор букв). Каждая переменная имеет
имя, тип и значение. Прежде чем использовать переменную, ее необходимо
объявить. После того как переменная объявлена, ей можно присвоить
значение.
Объявление переменных состоит из указания типа и имени переменной.
int myAge;
String myName;
boolean isTired;
Здесь переменная myAge имеет целочисленный тип, myName – текстовая,
isTired – логическая (принимает значения true или false).
Переменная может быть объявлена в любом месте метода, хотя
рекомендуется объявлять переменные в начале метода.
public static void main (String args[]) {
int count;
String title;
boolean isAsleep;
}
Несколько переменных одного типа могут быть объявлены через
запятую.
int x, y, z;
String firstName, LastName;
Во время объявления переменной можно присваивать ей значение.
int myAge= 29;
String myName = "Pustovoitov";
boolean isMarried = false;
int a = 4, b = 5, c = 6;
Имя переменной может начинаться с буквы, символа подчеркивания или
знака доллара. Переменные не могут начинаться с цифры. После первой
буквы имя переменной может содержать любую букву или цифру.

Таблица 1 – Целочисленные типы данных


Тип Размер Диапазон
byte 8 bits -128 to 127
short 16 bits -32,768 to 32,767
int 32 bits -2,147,483,648 to 2,147,483,647
long 64 bits -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

6
Таблица 2 – Другие типы данных
Тип Название Пример
float Дробный тип float f=(float)3.5;
double Дробный тип двойной точности double d=3.1234567;
String Строковый или текстовый String cityName = "Kharkiv";
char Символьный String firstLetter = ‘K’;
boolean Логический Принимает только значения
true или false

Таблица 3 – Арифметические операции


Оператор Название операции Пример
+ Сложение 3+4
- Вычитание 5-7
* Умножение 5*5
/ Деление 14 / 7
% Остаток от деления 20 % 7

Пример.
Программа выполняет поочередно сложение, вычитание, деление значений
двух переменных и ищет остаток от деления первой переменной на вторую.
package prg1;
import java.lang.*;
class ArithmeticTest {
public static void main (String args[]) {
short x = 6;
int y = 4;
System.out.println("x равен " + x + ", y равен " + y);
System.out.println("x + y = " + (x + y));
System.out.println("x - y = " + (x - y));
System.out.println("x / y = " + (x / y));
System.out.println("x % y = " + (x % y));
}
}
Результат.
x равен 6, y равен 4
x + y = 10
x-y=2

7
x/y=1
x%y=2
При написании программ необходимо следить за тем, чтобы название
класса совпадало с названием файла с расширением .java. Таким образом,
классу ArithmeticTest будет соответствовать файл ArithmeticTest.java.

1.3. Присваивание

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


способом.
x = y = z = 0;
Таким образом, во все три ячейки памяти записывается значение 0.
x = x + 2;
Это значит, что к значению переменной x прибавляется 2, а результат
записывается в переменную x, затирая, при этом, старое значение.
Если до выполнения операции x = x + 2 в переменной х было записано
число 5, то после операции в ней будет храниться число 7.

Таблица 4 – Операторы присваивания


Выражение Значение
x += y x=x+y
x -= y x=x-y
x *= y x=x*y
x /= y x=x y
x++ или ++x Инкремент x=x+1
x-- Декремент x=x-1

Пример.
Программа показывает разницу между вычислениями y=x++ и y=++x. В случае
y=x++ в переменную y записывается значение х, а потом значение х
увеличивается на единицу. В случае y=++x сначала х увеличивается на
единицу, а потом новое значение х записывается в у.
class PrePostFixTest {
public static void main (String args[]) {
int x = 0;
int y = 0;
System.out.println("x и y равны " + x + " и " + y );
x++;

8
System.out.println("x++ результат " + x);
++x;
System.out.println("++x результат " + x);
System.out.println("Обнуляем х");
x = 0;
System.out.println("------------");
y = x++;
System.out.println("y = x++ :");
System.out.println("x = " + x);
System.out.println("y = " + y);
System.out.println("------------");
y = ++x;
System.out.println("y = ++x :");
System.out.println("x = " + x);
System.out.println("y = " + y);
System.out.println("------------");
}
}
Результат.
x и y равны 0 и 0
x++ результат 1
++x результат 2
Обнуляем х
------------
y = x++ :
x=1
y=0
------------
y = ++x :
x=2
y=2
------------

1.4. Порядок выполнения простых математических операций

Вычислим следующие значения функций.


y = 6 + 4 / 2;
y = (6 + 4) / 2;
Результат будет различен, потому что операция деления имеет больший
приоритет, чем операция сложения. Поэтому, в первом случае результат будет

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

Таблица 5 – Приоритет выполнения операторов


Оператор Пояснение
() Скобки обладают максимальным
приоритетом
++ -- ! ~ Инкремент, декремент, отрицание
*/% Умножение, деление, остаток от деления
+- Сложение вычитание
<< >> >>> Операторы двоичного сдвига
< > <= >= Операторы сравнения
== != Равно, неравно
& AND
^ XOR
| OR
&& Логическое AND
|| Логическое OR
= += -= *= /= %= ^= Присваивания
&= |= <<= >>= >>>= Другие присваивания

1.5. Преобразования числовых типов

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


другой. На рисунке 2 показаны разрешенные преобразования.
Шесть черных стрелок (рис. 2) обозначают преобразования, которые
выполняются без потери информации. Три серые стрелки означают
преобразования, при которых может произойти потеря точности. Например,
количество цифр в большом целом числе 123456789 превышает количество
цифр, которое может быть представлено типом float. Число, преобразованное в
тип float, имеет правильную величину, но несколько меньшую точность.
int n = 123456789; float f = n; // Число n равно 1.234S67892E8.
Если два значения объединяются бинарным оператором (например n+f,
где n -целое число, a f - число с плавающей точкой), то перед выполнением
операции оба операнда преобразовываются в числа, имеющие одинаковый
тип.

10
byte short int long

float double
Рисунок 2 – Преобразование типов данных

Если хотя бы один из операндов имеет тип double, то второй тоже


преобразовывается в число типа double. В противном случае, если хотя бы
один из операндов имеет тип float. то второй тоже преобразовывается в число
типа float. В противном случае, если хотя бы один из операндов имеет тип long,
то второй тоже преобразовывается в число типа long. В противном случае оба
операнда преобразовываются в числа типа int.

1.6. Приведение числовых типов

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


типа int автоматически преобразовываются в значения типа double. С другой
стороны, есть несколько очевидных ситуаций, когда число типа double
рассматривается как целое. Преобразования чисел в языке Java возможны,
однако, разумеется, при этом может происходить потеря информации. Такие
преобразования называются приведением типа. Синтаксически приведение
типа задается парой скобок, внутри которых указывается желательный тип, а
затем - имя переменной. Например,
double х = 9.997;
int nx = (int)x;
Теперь в результате приведения значения с плавающей точкой к целому
типу переменная nx равна 9, поскольку при этом дробная часть числа
отбрасывается.
Если нужно округлить число с плавающей точкой до ближайшего целого
числа (что во многих случаях является намного более полезным),
используется метод Math.round.
double x = 9.997;
int nx = (int)Math.round(x) ;

11
Теперь переменная nx равна 10. При вызове метода round по-прежнему
нужно выполнять приведение (int), поскольку возвращаемое им значение
имеет тип long, и присвоить его переменной типа int можно лишь с помощью
явного приведения.
При попытке привести число одного типа к другому результат может
выйти за пределы допустимого диапазона. В этом случае результат будет
усечен. Например, выражение (byte) 300 равно 44. Поэтому, рекомендуется
явно проверять заранее, будет ли результат лежать в допустимом диапазоне
после приведения типов.

1.7. Математические операции и вычисления

Язык программирования java предлагает программистам для


использования мощный пакет математических функций. Функции хранятся в
классе java.lang.Math. Следовательно, нужно подключить к программе пакет
java.lang. Добавляем следующую строчку к началу программы: import java.lang.*;
Пример.
Требуется вычислить модуль числа (-5).
package prg1;
import java.lang.*;
public class FirstProg{
public static void main(String [] args){
System.out.println(Math.abs(-5));
}
}
Результат.
5
В программе выполняется обращение к классу математических функций
java.lang. Math и, в частности к функции Math.abs, которая вычисляет
абсолютное значение числа (-5). Для выполнения других математических
операций можно использовать функции, представленные в таблице 6 (На
самом деле в таблице представлен не весь список функций, предлагаемый
java. За полным перечнем необходимо обратиться к официальной
документации).
Таблица 6 – Математические операции

12
Тип
возвращаемого Название функции и ее описание
значения
double abs(double a) Возвращает модуль числа а
double ceil(double a) Вычисляет потолок числа.
Наименьшее целое число, которое больше заданного..
double cos(double a) Вычисляет косинус.
double exp(double a) Возводит число е в степень числа а.
double floor(double a) Возвращает пол числа. Т.е.
наибольшее целое число, которое меньше заданного
double log(double a) Вычисляет натуральный логарифм по
основанию а
double max(double a, double b) Выдает большее из
заданных чисел.
double min(double a, double b) Выдает меньшее из
заданных чисел.
double random() Возвращает случайное число с
положительным знаком, которое больше 0.0 и
меньше 1.0
double round(double a) Выполняет математическое
округление числа
double sin(double a) Вычисляет синус
double sqrt(double a) Вычисляет положительный
квадратный корень
double tan(double a) Вычисляет тангенс.

Пример.
x y
Программа вычисляет значение функции  2 x 2  3x  7 , при условии,
xy
что x  2 , y  4 .
package prg1;
import java.lang.*;
public class MathProg{
public static void main(String [] args){
double x=2;
double y=4;
double z;

13
z=(x+y)/(x-y)+2*Math.pow(x,2)*+3*x+7;
System.out.println(z);
}
}
Результат.
52.0
Пример.
1
Программа вычисляет значение функции  e 2b  ab , при a  4 , b  1 .
a
public static void main(String [] args){
double z;
double a=4, b=1;
z=Math.abs(1/a)+Math.exp(2*b)+Math.sqrt(a*b);
System.out.println(z);
}
Результат.
9.63905609893065
Пример.
a2 b2
Программа вычисляет значение функции e , при a  4 , b  3 .
public static void main(String [] args){
double a=4, b=3;
System.out.println(Math.exp(Math.sqrt(Math.pow(a,2)+Math.pow(b,2))));
}
Результат.
148.4131591025766

2. Логические ветвления программ


2.1. Блоки операторов

Блок операторов - группа операторов, заключенных в фигурные скобки


{}. Также, есть возможность создавать блок, вложенный в другой блок и т.п.
Блок ограничивает диапазон действия переменных. Переменная, объявленная
внутри блока, используется только в его пределах, за пределами блока ее
использовать нельзя.
Пример.
Пример демонстрирует использование блоков операторов.
public static void main(String [] args){

14
int x = 10;
{ // начало блока
int y = 50;
System.out.println("inside the block:");
System.out.println("x:" + x);
System.out.println("y:" + y);
} // конец блока
}
Если необходимо использовать переменную в блоке и за его пределами,
то следует объявить переменную перед блоком.
В примере показано, что переменная y может быть использована только
внутри блока, а переменная х – в любом месте метода main.

2.2. Оператор ветвления if

До этого момента все программы в примерах выполнялись


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

В общем виде оператор if имеет вид.


if(условие){
блок операторов 1
}else{
блок операторов 2
}

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


условие выполняется (т.е. оно истинно), то выполняются операторы из
первого блока, который следует за ключевым словом if, в противном случае
выполняются операторы из второго блока, который следует за ключевым
словом else.

15
истинно ложно
Если УСЛОВИЕ

ОПЕРАТОР ОПЕРАТОР
если если
истинно ложно

продолжение

Рисунок 3 – Оператор if else


Пример.
Программа, сравнивает две переменные и выдает на экран сообщение о том,
какая из переменных больше.
int x=5,y=4;
if (x < y){
System.out.println("x меньше y");
}else{
System.out.println("у меньше х");
System.out.println("или");
System.out.println("у равен х");
}
Результат.
у меньше х
или
у равен х

Таблица 7 – Операторы сравнения


Оператор Значение Пример
== Равно (два знака равно) x == 3
!= Неравно x != 3
< Меньше чем x<3
> Больше чем x>3
<= Меньше либо равно x <= 3
>= Больше либо равно x >= 3

16
Сокращенный оператор if использует только первую половину без else. В
общем виде он выглядит так.
if(условие){
блок операторов 1
}

истинно ложно
Если УСЛОВИЕ

ОПЕРАТОР

продолжение

Рисунок 4 – Блок-схема сокращенного оператор if

Пример.
Программа проверяет переменную х, если она равна тройке, то на экран
выдается надпись «тройка».
if(x==3){
System.out.println("тройка");
}
В операторе if можно задавать сложное условие, которое может состоять
из нескольких простых условий, соединенных между собой логическими
операторами.

Таблица 8 – Логические операторы


Буквенное значение Символьное значение Описание
and && И
or || ИЛИ
not ! Отрицание
!= Неравно

17
Оператор if со сложным условием в общем виде имеет следующий вид.
if((условие1)&&(условие2)&&…&&(условиеN)){
блок операторов 1
}
Пример.
Программа проверяет переменную х. Если она окажется больше нуля и
одновременно меньше десяти, то на экран будет выдана надпись
«положительное число меньше десяти».
double x = Math.random()*100;
if((x>0)&&(x<10)){
System.out.println("положительное число меньше десяти");
}
Оператор if может быть вложен в другой оператор if. Тогда, если
выполняется условие главного if, мы попадаем в первый блок операторов, в
котором находится еще один if, принцип работы которого подобен главному
if. Вложенность условных операторов if может быть бесконечной.
Пример.
Программа должна выдать на консоль в зависимости от значения переменной
а следующие надписи: «a больше 0», «a меньше 0», «a равно 0».
if(a>0){
System.out.println(“a больше 0”);
}else{
if(a<0){
System.out.println(“a меньше 0”);
}else{
System.out.println(“a равно 0”);
}
}
Пример.
Программа «Калькулятор1», выполняет сложение, вычитание, умножение и
деление двух переменных x и y. Значение операции задается в символьной
переменной oper.
int x=5;
int y=3;
char oper=’+’;
int z=0;
if(oper==’+’){
z=x+y;
}

18
if(oper==’-’){
z=x-y;
}
if(oper==’*’){
z=x*y;
}
if((oper==’/’)&&(y!=0)){
z=x/y;
}
System.out.println(z);
В результате выполнения программы на консоль будет выдан результат
«8». Если переменной oper присвоить значение «-», то результатом
выполнения программы будет «2». Если «*», то результатом будет «15». Если
же в переменную oper записать значение «%», то на экран будет выдан
результат «0». Так как не одно условие оператора if не будет выполнено,
компилятор не попадет не в один из внутренних блоков оператора if,
следовательно, значение переменной z не будет изменено, и на экран будет
выдано начальное значение z, т.е. «0».
Пример.
Программ отыскивает значения корней квадратного уравнения в зависимости
от значений параметров a,b,c.
package equations;
import java.lang.*;
public class SEquation {
public static void main(String[] argv) {
float a=3,b=4,c=5;
if(a==0){
System.out.println("Корень уравнения:"+(-c/b));
}else{
double d=b*b-4*a*c;
if(d<0){
System.out.println("Корней нет");
}else{
double x1,x2;
x1 =(-b+Math.sqrt(d))/2*a;
System.out.println("Корень уравнения 1: "+x1);
x2 =(-b-Math.sqrt(d))/2*a;
System.out.println("Корень уравнения 2: "+x2);
}
}
}
}

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

2.3. Оператор варианта switch

Условный оператор if в зависимости от условия выполняет один из двух


блоков операторов. Оператор варианта switch позволяет выполнить один или
несколько блоков операторов из некоторого множества в зависимости от
значений некоторой переменной. В общем виде оператор switch имеет вид.
switch (Название переменной) {
case Значение1:
Блок переменных 1;
break;
case Значение2:
Блок переменных 2;
break;
case Значение3:
Блок переменных 3;
break;
...
default: Блок переменных выполняемых по умолчанию;
}
После ключевого слова switch в скобках указывается переменная,
значения которой будут проверяться в каждом из case. В случае совпадения
значения case со значением проверяемой переменной будут выполнены все
блоки операторов, начиная с контрольного. Если необходимо выполнить
только один блок, то в нем необходимо поставить оператор break, который
закончит выполнение оператора switch, и проверки на этом закончятся.
Пример.
Программа выдает на консоль буквенную надпись цифры, которая хранится в
переменной val.
String convertNum(int val) {
switch (val) {
case 0: return "нуль ";

20
case 1: return "один ";
case 2: return "два ";
case 3: return "три ";
case 4: return "четыре ";
case 5: return "пять ";
case 6: return "шесть ";
case 7: return "семь ";
case 8: return "восемь ";
case 9: return "девять ";
default: return " ";
}
}
Пример.
Программа калькулятор 2.
switch (oper) {
case '+':
z=x+y;
break;
case '-':
z=x-y;
break;
case '*':
z=x*y;
break;
case '/':
z=x/y;
break;
}

2.4. Циклы

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


и тех же действий. Вместо того чтобы многократно набирать какую-то
последовательность одинаковых операторов, можно эти операторы заключить
в тело цикла и указать количество повторений. Либо поместить операторы в
тело цикла для неизвестного заранее количества повторений, но указав при
этом некоторое условие окончания цикла.
Циклы бывают двух видов: цикл со счетчиком for и цикл с проверкой
условия while. Оператор while используется для задавания цикла с проверкой
некоторого условия нахождения в цикле. Если условие перестает

21
выполняться, то цикл заканчивается. Оператор while в свою очередь делится
на две подгруппы. Оператор while с предусловием и постусловием.
В общем виде оператор while с предусловием имеет следующий вид:
while(условие нахождения в цикле){
Оператор 1
Оператор 2
……………
};

ложно
П Проверить УСЛОВИЕ
О
В истинно
Т
О
Р
ОПЕРАТОР
И
Т
Ь

продолжение

Рисунок 5 – Блок-схема оператора while с предусловием

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


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

22
Пример.
Требуется вывести на экран положительные числа до 9.
public static void main(String[] args) {
int i=0;
System.out.println(“Начало программы”);
System.out.println(“Операторы до цикла”);
while(i<=9){
System.out.print(i);
i++;
};
System.out.println(“ ”);
System.out.println(“Операторы после цикла”);
System.out.println(“Конец программы”);
}
Результат.
Начало программы
Операторы до цикла
0123456789
Операторы после цикла
Конец программы
Работа программы начинается с того, что объявляется переменная i и в
нее записывается значение 0, затем выводится надпись “Операторы до цикла”.
Затем в операторе while происходит проверка значения переменной i. Т.к. i
меньше девяти, то условие выполняется и компилятор входит в тело цикла,
где на экран выдается значение переменной, т.е. на экран выдается «0». Затем
значение переменной i увеличивается на единицу (т.е. теперь i равно «1»).
Первый шаг закончился, и компилятор возвращается на проверку условия.
Т.к. i все еще меньше «9», попадаем опять в тело цикла. Снова выводим на
экран значение переменной i (i равно «1»). Опять происходит увеличение i на
единицу. Действия повторяются до тех пор, пока во время проверки условия
(т.е. сравнивания переменной i с числом «9») не будет обнаружено, что
значение i равняется «9». Это значит, что условие не выполняется, и
компилятор в тело цикла не войдет, а продолжит выполнение операторов,
следующих за циклом.

23
Таким образом, понятно, что в задачи одного шага цикла входит:
печатать значение переменной i и увеличивать ее значение на единицу. Шаги
выполняются до тех пор, пока значение i не достигнет девяти.
Оператор while с постусловием, (иначе он называется do while) имеет
следующий вид
do{
Оператор 1
Оператор 2
Оператор 3
……………
……………
Оператор N
}while(условие нахождения в цикле);
Отличие от предыдущего примера состоит в том, что сначала
выполняется шаг цикла, а потом происходит проверка условия. Таким
образом, при использовании оператора do while, первый шаг цикла
выполняется в любом случае, а последующие до тех пор, пока выполняется
условие.

П
О
В ОПЕРАТОР
Т
О
Р
И истинно
Т
Ь Проверить УСЛОВИЕ

ложно

продолжение

Рисунок 6 – Блок-схема оператора do while с постусловием

24
Оператор for задает цикл со счетчиком. Он используется только в тех
случаях, когда количество повторений известно заранее. Для выполнения
цикла требуется задать переменную-счетчик целого типа, которая будет
отвечать за количество повторений. Необходимо задать ее начальное и
конечное значение, а также ее шаг (прирост или дельта) за каждое повторение
цикла (дельта). Оператор for имеет следующий вид.
for(int i=S; i<E; i++){
Оператор 1
Оператор 2
……………
}
Здесь for – ключевое слово, обозначающее начало цикла. Запись int i=S
значит, что объявляется переменная целого типа, и ей присваивается
начальное значение, например S (вместо S может быть подставлено любое
число). Далее указывается конечное значение переменной i (до какого
значения i надо выполнять повторения) – i<E. И, наконец, i++ значит, на какую
величину будет изменяться переменная i за каждое повторение цикла.
Пример.
Программа должна вывести в столбик числа от 1 до 10. Программу можно
написать двумя способами. Первый способ без использования циклов, второй
с использованием циклов.
public static void main(String[] args) { public static void main(String[] args) {
System.out.println(“1”); for(int i=1;i<=10;i++){
System.out.println(“2”); System.out.println(i);
System.out.println(“3”); }
System.out.println(“4”); }
System.out.println(“5”);
System.out.println(“6”);
System.out.println(“7”);
System.out.println(“8”);
System.out.println(“9”);
System.out.println(“10”);
}
В принципе, программы выполняют одни и те же действия, но во втором
примере написано гораздо меньше текста. Это достигается за счет
использования циклов для повторения одного и того же фрагмента
определенное количество раз. Если бы программа должна была выводить на
экран числа от единицы до миллиона, то в первом случае пришлось бы

25
дописывать около миллиона строк программного кода, а во втором примере
количество строк текста программы осталось бы неизменным, изменилось бы
только 10 на 1000000 при указании конечного значения переменной i.
Смысл второго примера состоит в том, что повторяющийся оператор
System.out.println заключается в цикл с переменной i в качестве счетчика.
Указывается начальное значение переменной i=1. Указывается величина, на
которую будет увеличиваться переменная i за каждое повторение цикла, i++ –
значит, что увеличение будет производиться на единицу. Устанавливается
значение предела, до которого будет выполняться цикл. В примере указано,
что i<=10, это значит, что i, увеличиваясь за каждый шаг на единицу, достигнет
значения 10. На каждом повторении цикла происходит выполнение оператора
System.out.println, который выводит на экран значение переменной i. Т.к.
повторений 10, то количество выполнений в программе оператора
System.out.println будет тоже 10, причем при каждом его последующем вызове
значение i будет больше на единицу, чем при предыдущем.

3. Массивы
3.1. Одномерные массивы

Массив - это последовательность объектов, либо примитивных типов


данных, которые имеют одинаковый тип и упакованы вместе под одним
именем идентификатора. Другими словами, массив – это какая-то переменная,
которая содержит в себе несколько переменных одинакового типа. Они, в
свою очередь, являются ячейками массива и имеют порядковый номер. В java
нумерация ячеек массива начинается с нуля. Графически массив можно
представить следующим образом.
0 1 2 3 4 … N

Прежде, чем использовать переменную типа массив, ее следует объявить


и инициализировать. Для определения массива указывается имя типа, за
которым следуют пустые квадратные скобки.
int[] a;
Можно также поместить квадратные скобки после идентификатора, что
имеет тот же самый смысл.
int a[];
В этом месте программы компилятору будет указано, что переменная а
является массивом целых чисел, длина массива не указывается. В этой точке

26
определяется только ссылка на массив, но здесь не резервируется место в
памяти под массив. Создание хранилища для массива описывается
выражением инициализации. Для массивов, инициализация может быть
выполнена в любом месте кода.
a = new int[10];
Здесь компилятору сообщается, что переменной а выделяется память под
10 элементов целого типа. Т.е. массив а будет иметь 10 ячеек (или состоять из
десяти переменных), в каждую из которых может быть записано целое
значение.
Для того чтобы записать или считать значение из ячейки массива
необходимо указать имя массива и номер ячейки в квадратных скобках.
Принцип работы с каждой отдельной ячейкой массива подобен работе с
обычной переменной.
a[0]=5;
a[1]=9;
a[2]=a[0]+a[1];
System.out.println(a[0]+” ”+a[1]+” ”a[2]);
Здесь в ячейку под номером «0» (самая первая ячейка массива)
записывается число «5». В первую записывается «9». Во вторую записывается
сумма значений нулевой и первой. Затем выводятся на консоль значения всех
трех ячеек.
При инициализации массива можно задавать значения ячеек. Для этого
после объявления массива в фигурных скобках через запятую указываются
значения. Количество значений будет показывать размер массива.
int[] marks = {2, 3, 4, 5};
String[] teams = {”Metallist” , ”Shakhtar” , “Dinamo” , “Dnipro”};
Заданы массивы, состоящие из четырех элементов. Первый массив –
массив целых чисел. Второй – массив строк.
Если выполнить команду
System.out.println(teams[1]+ “ 1:1 ” + teams[2]);
System.out.println(teams[3]+ “ 0:3 ” + teams[0]); ,
то на экран будет выдана надпись
Shakhtar 1:1 Dinamo
Dnipro 0:3 Metalist.
У каждого созданного массива помимо хранилища данных в памяти
выделяется место под специальные свойства и методы. Например, с
помощью свойства length можно узнать количество элементов массива.

27
Пример.
Необходимо заполнить массив случайными целыми числами от нуля до ста.
Затем вывести элементы в столбик на консоль.
package arrTest;
import java.lang.*;
public class Tst1 {
public static void main(String[] argv) {
int[] a = new int[10]; //объявление массива целых чисел
//заполнение массива случайными числами
for(int i=0;i<a.length;i++){
a[i] = (int)Math.round(Math.random()*100);
}
//вывод массива на экран
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
}
Здесь, сначала объявляется массив целых чисел, который состоит из
десяти элементов. Потом в цикле от 0 (int i=0) до количества элементов в
массиве (i<a.length) выполняется цикл по i с шагом 1 (i++). Т.к. элементов в
массиве – 10, то и количество шагов цикла будет 10. Причем на каждом шаге
переменная i будет принимать значения 0,1,2,…,9, а ячейка a[i] будет иметь
номер a[0], a[1], a[2], … a[9]. Таким образом, на каждой итерации цикла в массив,
в ячейку под номером i будет записываться случайное число от 0 до 100 (a[i] =
(int)Math.round(Math.random()*100);)
Вывод значений массива на экран осуществляется подобным образом.
Задается цикл, где переменная i изменяется от 0 до a.length с шагом 1. На каждом
шаге цикла происходит обращение к одной ячейке массива, номер которой равен i. Эта
ячейка выводится на экран. Всего выполняется a.length шагов цикла.
Пример.
Требуется создать массив из 100 элементов, заполнить его случайными
числами от 20 до 50. Посчитать сумму всех элементов массива, а также
среднее арифметическое значение.
package arrTest;
import java.lang.*;
public class Tst2 {
public static void main(String[] argv) {
int[] a = new int[100];
for(int i=0;i<a.length;i++){ //заполнение массива случайными числами

28
a[i] = (int)Math.round(Math.random()*30)+20;
}
int sum=0; //накопительная переменная
for (int j = 0; j < a.length; j++) {
sum+=a[j]; //значение каждой ячейки добавляется к переменной sum
}
System.out.println("Сумма: "+sum);
System.out.println("Среднее значение: "+sum/(float)a.length);
}
}
Здесь, после инициализации массива и заполнения его случайными
числами, создается накопительная переменная sum, которая перед проходом
по всем элементам массива обнуляется. В следующем цикле по переменной j
от 0 до a.length происходит обращение к каждой ячейке массива, значения
которых на каждом шаге цикла прибавляется к переменной sum. Работа
программы, выполняющей накопление значения для четырех шагов цикла,
показана в таблице 9. В конечном счете, в переменной sum будет записана
сумма всех ячеек массива.

Таблица 9 – Операция sum+=a[j]; по шагам


Текущая ячейка
Шаг цикла (j) Значение переменной sum
на шаге цикла
Перед циклом 0
0 a[0] 0+a[0]
1 a[1] 0+a[0]+a[1]
2 a[2] 0+a[0]+a[1]+a[2]
3 a[3] 0+a[0]+a[1]+a[2]+a[3]

Для расчета среднего арифметического значений элементов массива,


необходимо значение переменной sum разделить на длину массива a.length.
Пример.
Найти значение минимального элемента массива и указать номер ячейки.
package arrTest;
import java.lang.*;
public class Tst3 {
public static void main(String[] argv) {
int[] a = new int[20];
for(int i=0;i<a.length;i++){
a[i] = (int)Math.round(Math.random()*30)+20;

29
}
int minElem=a[0]; //для запоминания минимального значения
int minCell=0; //для запоминания номера минимальной ячейки
for (int j = 0; j < a.length; j++) {
if(a[j]<minElem){ //если появилась новая минимальная ячейка, то
minElem = a[j]; //запоминаем новый минимальный элемент
minCell=j; //запоминаем номер новой минимальной ячейки
}
}
System.out.println("Ячейка: "+minCell);
System.out.println("Значение: "+minElem);
}
}
Для поиска минимального элемента необходимо обойти весь массив,
сравнивая каждый элемент массива с некоторой вспомогательной переменной
minElem. Вначале присвоим переменной minElem значение нулевой ячейки и
запомним ее номер в minCell. Таким образом, полагаем, что до начала поиска
нулевая ячейка содержит минимальное значение.
int minElem=a[0];
int minCell=0;
Затем в цикле от нуля до длины массива сравниваем значение minElem со
значением каждой ячейки массива. Если значение ячейки a[j] будет меньше,
чем значение minElem, то это значит, что необходимо запомнить новый
минимальный элемент в minElem, затерев ее старое значение.
if(a[j]<minElem){
minElem = a[j];
minCell=j;
}
А в переменную minCell запомнить номер нового минимального элемента
массива, а старый номер затереть.

3.2. Двумерные массивы

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


переменную, которая состоит из множества ячеек, но имеет уже вид матрицы.
Здесь номер ячейки задается двумя координатами, номером столбца и строки.
Объявление массива происходит следующим образом: указывается тип
данных, затем следует две пары квадратных скобок, затем имя переменной.
float [][] f;

30
Две пары квадратных скобок показывают, что массив является
двумерным.
Во время инициализации необходимо указать размерность массива, т.е.
задать количество столбцов и строк – f = new float[8][8]; или float f = new float[8][8];
В примере задается двумерный массив 8х8, который структурой
напоминает шахматную доску, в каждую клетку которой можно записать
число типа float. Принцип работы с двумерным массивом напоминает принцип
работы с одномерным, только при указании ячейки надо задавать две
координаты вместо одной. Графически двумерный массив MxN можно
представить следующим образом.
0 1 2 3 4 … N
0
1 5
2 7
M
В примере в ячейке a[1][1] записано число «5». В ячейке a[2][4] записано число
«7».
Для того чтобы записать или считать значение из ячейки двумерного
массива необходимо указать имя массива, номер столбца в квадратных
скобках, затем номер строки в квадратных скобках. Принцип работы с каждой
отдельной ячейкой массива подобен работе с обычной переменной.
a[0][0]=1; a[0][1]=2; a[0][2]=3;
a[1][0]=4; a[1][1]=5; a[1][2]=6;
a[2][0]=7; a[2][1]=8; a[2][2]=9;
Пример.
Создать двумерный массив 5х10 и заполнить его случайными числами. Затем
вывести массив на консоль в виде матрицы 5х10.
package arrays;
import java.lang.*;
public class ArrTst1 {
public static void main(String[] argv) {
//объявление массива
int[][] f = new int[5][10];
//заполнение массива случайными двузначными числами
for(int i=0;i<5;i++){
for(int j=0;j<10;j++){
f[i][j] = (int)Math.round(Math.random()*(double)89)+10;
}

31
}
//вывод массива на экран
for(int k=0;k<5;k++){
for(int m=0;m<10;m++){
System.out.print(f[k][m]+" ");
}
System.out.println();
}
}
}
Результат.
83 27 59 89 47 98 97 93 65 85
13 72 17 94 53 96 57 32 72 80
86 16 49 90 88 43 27 64 68 12
41 85 75 21 58 40 59 51 69 41
86 27 58 42 90 81 14 20 70 39
Пример.
Создать двумерный массив 8х8. Заполнить его числами 0 и 1 в шахматном
порядке.
package arrays;
import java.lang.*;
public class ArrTst2{
public static void main(String[] argv) {
int[][] f = new int[8][8];
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
if((i+j)%2==0){
f[i][j]=1;
}else{
f[i][j]=0;
}
}
}
for(int k=0;k<8;k++){ //вывод массива на экран
for(int m=0;m<8;m++){
System.out.print(f[k][m]+" ");
}
System.out.println();
}
}
}
Результат.

32
10101010
01010101
10101010
01010101
10101010
01010101
10101010
01010101
Пример.
Создать массив 8х8, заполнить его случайными двузначными числами.
Вывести на консоль элементы двух главных диагоналей.
package arrays;
import java.lang.*;
public class ArrTst3{
public static void main(String[] argv) {
int[][] f = new int[8][8];
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
f[i][j] = (int) Math.round(Math.random() * (double) 89) + 10;
}
}
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
System.out.print(f[i][j] + " ");
}
System.out.println();
}
System.out.println();
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if ( (i == j) || (j == 8 -1- i)) {
System.out.print(f[i][j]+" ");
}
}
}
}
}
Результат.
30 72 30 79 28 47 39 27

33
68 69 49 34 63 42 44 95
46 69 61 43 74 41 32 34
56 47 91 53 40 59 41 90
44 84 69 89 49 96 24 28
39 34 78 51 40 62 79 26
27 79 93 26 76 87 76 15
71 17 15 92 98 73 91 35

30 27 69 44 61 41 53 40 89 49 78 62 79 76 71 35

4. Строковые типы данных в java


4.1. Строки

Строки – это последовательности символов, например "Hello". В языке


Java нет встроенного типа для строк. Вместо этого стандартная библиотека
языка Java содержит встроенный класс String. Каждая строка, заключенная в
кавычки, представляет собой экземпляр класса String.
String e = ""; // Пустая строка.
String greeting = "Hello";
Язык Java, как и большинство языков программирования, дает
возможность использовать знак + для объединения (конкатенации) двух
строк.
String expletive = "Вставка";
String PG13 = "удаленная";
String message = expletive + PG13;
Код, приведенный выше, присваивает переменной message строку
"Вставкаудаленная". (Обратите внимание на отсутствие пробела между
словами: знак + объединяет две строки точно в указанном порядке.).
При конкатенации строки со значением, которое строкой не является, это
значение преобразовывается в строку. Например, код
int age = 13;
String rating = "PG" + age;
присваивает переменной rating строку "PG13".
Это свойство широко используется в операторах вывода. Например,
оператор
System.out.println("Ответ равен " + answer);

34
выводит на печать все, что требуется (причем вставляет пробел после слова
"равен").

4.2. Подстроки

С помощью метода substring класса String можно выделить подстроку из


заданной строки. Например, код
String greeting = "Hello";
String s = greeting.substring(0, 4);
образует строку, состоящую из символов "Hell". В языке Java символы в
строке подсчитываются довольно своеобразно: первый символ строки
занимает нулевую позицию.
Например, символ 'H' в строке “Hello” занимает нулевую позицию, а
символ 'о' четвертую. Таким образом, первый параметр метода substring
задает позицию символа в строке greeting, с которого будет начинаться новая
подстрока. Второй параметр метода substring задает позицию символа, кото-
рый уже не попадет в подстроку. Допустим, необходимо скопировать
символы из позиций 0, 1, 2 и 3 (от позиции 0 до позиции 3 включительно), т.е.
метод substring будет копировать символы из позиций от 0 до 4
исключительно.
Такой способ имеет определенное преимущество: легко вычислить длину
подстроки. Строка s.substring(a, b) всегда состоит из b-а символов. Например,
подстрока "Неll" имеет длину 4-0 = 4.

4.3. Редактирование строки

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

например:
String greeting = "Hello";
int n = greeting.length () ; // Длина строки равна 5.
Если тип char означает символ в формате Unicode, то класс String означает
последовательность символов в кодировке Unicode. Из строки можно
выделить отдельный символ. Вызов метода s.charAt(n) возвращает символ в

35
кодировке Unicode, находящийся в позиции n, где число n лежит в диапазоне
от 0 до s.length() - 1, например:
char last = greeting. charAt (4); // Четвертый символ - 'о'.
Однако класс String не дает методов, позволяющих изменить символ в
заданной строке. Нет возможности просто изменить последнюю позицию в
строке greeting, поместив в нее восклицательный знак, чтобы преобразовать
строку greeting в строку "Hell!". Для того чтобы модифицировать строку в
языке Java достаточно просто выделить подстроку, которую необходимо
оставить без изменения, и конкатенировать ее с символами, которые надо
поставить в нужные позиции:
greeting = greeting.substring(0, 4) + "!";
С помощью такого оператора можно присвоить переменной greeting

строку "Hell!".
Поскольку, программируя на языке Java, нет возможности изменять
отдельные символы в строке, (как число 3 всегда равно 3, так и строка "Hello"
всегда содержит символы 'Н', 'е', 'l' , 'l' и 'о') то изменить эти значения
напрямую невозможно. Однако, как только что было показано, можно
изменить содержимое строковой переменной greeting и заставить ее ссылаться
на другую строку так же, как числовой переменной, в которой хранится число
3, можно присвоить число 4.
Не происходит ли при этом большой потери эффективности? Кажется,
было бы намного проще изменять символы, чем создавать новую строку
заново. Возможно, это и так. Действительно, неэффективно создавать новую
строку, образованную с помощью конкатенации строк "Hell" и "!". Однако
неизменяемые строки имеют одно большое преимущество: компилятор может
делать строки совместно используемыми.

4.4. Проверка строк на равенство

Чтобы проверить, совпадают ли две строки, следует использовать метод


equals; вызов метода s.equals(t) возвращает значение true, если строки s и t равны
между собой, в противном случае он возвращает значение false. Отметим, что

36
строки s и t могут быть как переменными, так и константами. Например,
выражение
"Hello!".equals(command);
вполне допустимо. Чтобы проверить идентичность строк, игнорируя различие
между прописными и строчными буквами, следует использовать метод
equalsIgnoreCase.
"Hello".equalsIgnoreCase("hello") ;
Для проверки строк на равенство нельзя применять оператор «!» Он
проверяет лишь, хранятся ли обе строки в одной и той же области памяти.
Разумеется, если обе строки хранятся в одном и том же месте, они должны
совпадать между собой. Однако вполне возможна ситуация, при которой
идентичные строки хранятся в разных местах.
String greeting = "Hello"; // Инициализирует
//переменную
// greeting строкой.
if (greeting = "Hello") .. .
// Возможно, это условие истинно.
if (greeting.substring (0, 4) == "Hell") ...
// Возможно, это условие ложно.
Если виртуальная машина всегда позволяет совместно использовать
одинаковые строки, то для проверки их равенства можно применять оператор
== (два знака «равно»). Однако совместно использовать можно лишь
константы, а не строки, являющиеся результатами таких операций, как + или
substring. Следовательно, либо нужно навсегда отказаться от проверок строк на
равенство с помощью оператора == (два знака «равно»), либо будет получена
программа, содержащая наихудшую из возможных ошибок –
перемежающуюся ошибку, появление которой невозможно предсказать.
Класс String в языке Java содержит более 50 методов. Неожиданно
большое количество из них оказались полезными, так что можно легко себе
представить, что они используются довольно часто. В таблице 10 дается
информация о некоторых методах класса String. В таблице представлены не
все методы класса String. За более полной информацией необходимо
обратиться к официальной документации.

37
Таблица 10 – методы класса String
Тип
выдав. Метод Пояснение
знач.
char charAt(int index) Возвращает символ, расположенный в
указанной позиции.
int compareTo(String other) Возвращает отрицательное значение, если
строка предшествует строке other в
лексикографическом порядке, положи-
тельное значение — если строка other
предшествует данной строке в
лексикографическом порядке, и 0 - если
строки идентичны.
boolea endsWith(String suffix) Возвращает значение true, если строка
n заканчивается подстрокой suffix.
boolea equals(Object other) Возвращает значение true, если строка
n равна строке other .
boolea equalsIgnoreCase(String Возвращает значение true, если строка
n other) равна строке other без учета различий
между прописными и строчными буквами.
int index(String str) Возвращает начало первой подстроки,
int indexOf(String str, int from) совпадающей со строкой str, начиная с
позиции 0 или frorm.
int lastlndexOf(String str) Возвращает начало последней подстроки,
int lastlndexOf(String str, int равной строке str, начиная с позиции 0 или
from) from.
int length() Возвращает длину строки.
String replace(char С1, char C2) Возвращает строку, полученную заменой
всех символов С1 в строке символом C2.
boolea startWith(String prefix) Возвращает значение true, если строка
n начинается подстрокой prefix.
String substring(int bx) Возвращает строку, состоящую из всех
String substring (int bx, int ex) символов, начиная с позиции bx и
заканчивая концом строки или позицией ex,
исключая его.
String toLowerCase() Возвращает новую строку, состоящую из
всех символов исходной строки, при этом
все прописные буквы преобразовываются в
строчные.
String toUpperCase() Возвращает строку, состоящую из всех
символов исходной строки, при этом все
строчные буквы преобразовываются в
прописные.
String trim() Возвращает новую строку, из которой
исключены все предшествующие и
замыкающие пробелы.

38
Пример.
Создать строку, занести в нее значение «Мама мыла раму». Вывести на
консоль строчку некоторое количество раз, причем при каждом последующем
выводе требуется обрезать в конце строки на один символ больше. Выполнять
вывод до тех пор, пока не закончатся символы в строке.
package sss;
public class sssClass{
public static void main(String[] argv) {
String st = "Мама мыла раму";
for(int i=0; i<st.length(); i++){
System.out.println(st.substring(0, st.length() – i ));
}
}
}
Результат.
Мама мыла раму
Мама мыла рам
Мама мыла ра
Мама мыла р
Мама мыла
Мама мыла
Мама мыл
Мама мы
Мама м
Мама
Мама
Мам
Ма
М

4.5. Считывание ввода

Уже было показано, как легко можно вывести информацию на


"стандартное устройство вывода" (т.е. консольное окно), вызвав метод
System.out.println. К сожалению, считать информацию со "стандартного
устройства ввода" (т.е. клавиатуры) немного сложнее.
Однако создать диалоговое окно для ввода данных с клавиатуры
достаточно легко. Вызов метода
JOptionPane.showInputDialog(promptString)

39
выводит на экран диалоговое окно, в котором пользователь может набрать
свои данные (рис. 7). Этот метод возвращает строку, набранную
пользователем в этом окне.

Рисунок 7 – Запрос на ввод данных

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


программы. String name = JOPtionPane.showinputDialog("What is your name?");
Чтобы считать число, нужно выполнить более сложную работу. Метод
JOptionPane.showInputDialog возвращает строку, а не число. Для преобразования
этой строки в число нужно использовать метод Integer.parselnt или
Double.parseDouble, например:
String input = JOptionPane. showInputDialog ("How old are you?") ;
int age = Integer.parselnt(input);
Если пользователь наберет на клавиатуре число 40, то строковой
переменной input будет присвоена строковое значение "40". Метод
Integer.parselnt преобразовывает строку в соответствующее число, т.е. 40.
Если параметр метода parselnt содержит символы, не являющиеся
цифрами, метод возбуждает исключительную ситуацию. Если программа не
"перехватывает" эту исключительную ситуацию, виртуальная машина
прекращает ее выполнение и выводит на консоль сообщение об ошибке.
Пример.
Программа запрашивает имя пользователя и его возраст, а затем выводит на
экран подобное сообщение: Здравствуй, Вася. В следующем году тебе,
возможно, исполнится 25.
import javax.swing.*;
public class InputTest{
public static void main(String[] a){
// Первый ввод.
String name = JOptionPane.showInputDialog("Ваше имя") ;
// Второй ввод.
String input = JOptionPane.showInputDialog("Ваш возраст") ;

40
//Необходимо преобразовать строку в целое число.
int age = Integer.parselnt(input);
// Вывод результата на консоль.
System.out.println("Здравствуй, " + name
+ ". В следующем году тебе, возможно, исполнится "
+ (age + 1) );
System.exit(0) ;
}
}
При выполнении этой программы сначала на экране возникнет
диалоговое окно, в котором нужно ввести имя пользователя. Затем это окно
исчезнет, и во вновь появившемся втором диалоговом окне нужно будет
ввести возраст пользователя. Результат работы программы будет выведен в
консольное, а не диалоговое окно.
Заметим, что программа завершает свою работу вызовом метода
System.exit(0);
Каждый раз, когда программа вызывает метод
JOptionPane.showsInputDialog, ее работу необходимо завершать вызовом метода
System.exit(0). В основном это вызвано техническими причинами. Вывод на
экран диалогового окна запускает новый поток управления. При завершении
работы метода main этот новый поток управления не прекращает свою работу
автоматически. Чтобы закрыть все потоки, нужно вызвать метод System.exit.
Метод System.exit получает целочисленный параметр, представляющий
собой "код выхода" из программы. По умолчанию, если работа программы
завершилась нормально, ее код выхода равен 0, в противном случае этот код
не равен нулю. Для индикации разных ошибочных ситуаций можно
использовать разные коды выхода.
В заключение необходимо обратить внимание на строку i
mport javax. swing.* ;
расположенную в начале программы. Класс JOptionPane определен в пакете
javax.swing. Используя класс, не определенный в основном пакете java.lang,
нужно применять директиву import.

5. Функции
5.1. Основы использования функций в JAVA

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


– функция main, с нее всегда начинается выполнение программы. На самом

41
деле, в рамках одного класса программы может быть несколько функций.
Функции также можно называть подпрограммами. Они имеют свои
собственные переменные и свою собственную логику.
Работу с функцией можно разделить на два этапа: описание (объявление)
функции и использование (вызов). Причем описание функции выполняется
один раз, а вызывать ее можно любое необходимое количество раз.
Описывают функции в любом порядке подряд в рамках класса, либо
перед функцией main, либо после нее, этот факт не существенный.
Независимо от количества функций в программе и порядка их объявления
всегда первой будет выполняться функция main, внутри которой надо
организовать вызов других функций класса.
public static void main(String[] a){
Оператор 1;
Оператор 2;
MyFuction(список входных параметров);
Оператор N;
MyFuction(список входных параметров);
………………..
}
public static void MyFunction(список входных параметров){
Блок операторов 1;
}
В данном примере помимо функции main описывается другая функция –
MyFunction,в задачи которой входит выполнение какого-то блока операторов,
при некотором условии, задаваемом в списке входных параметров. После
запуска программы начинается последовательное выполнение операторов
функции main. После выполнения первого и второго оператора происходит
вызов MyFuction с какими-то заданными параметрами, и программа
переключается на выполнение Блока операторов 1. После отработки функция
MyFuction передает работу функции main, которая продолжает выполнение
операторов, следующих за первым вызовом MyFuction. Далее выполняется
оператор N, после которого следует второй вызов функции MyFuction.
Следовательно, опять выполняется Блок операторов 1, которые находятся
внутри MyFuction.. Выполнив свои операторы, MyFuction опять передает работу
функции main, которая продолжает работу. Таким образом, некий текст
программы, написанный один раз в рамках функции MyFuction может быть
выполнен несколько раз.

42
При объявлении функции сначала указывается модификатор доступа, в
данном примере это public static. Через пробел указывается тип выдаваемого
параметра. В данном примере тип выдаваемого параметра – void, т.е.
выдаваемого параметра нет. Затем пишется имя функции, которое
формируется по принципу формирования имен переменных. В примере это –
MyFunction. После чего в круглых скобках через запятую указывается список
принимаемых переменных с указанием их типов. Например:
public static float MyFunction (int x, int y) { …. };
Описана функция, которая принимает два входящих параметра целого
типа, выполняет какие-то расчеты и выдает значение типа float.
Функция может не иметь входных параметров, тогда после имени
функции ставятся пустые круглые скобки. Собственно говоря, в тексте
программы можно отличить функцию от переменной по наличию круглых
скобок после имени.
После круглых скобок в фигурных скобках размещается внутренний
текст функции, это те блоки операторов, которые будут выполнены при
вызове функции. Функции могут иметь или не иметь выходной параметр. Тип
выходного параметра описывается перед названием функции. Если он равен
void, то это значит, что функция не выдает никаких результатов. В противном
случае, если перед названием функции указан какой-то тип данных (float,
double, int и т.п.), то это значит, что выдаваемые результаты будут иметь
указанный тип, а также делает обязательным наличие в конце функции
оператора return, который осуществляет выдачу выходного значения функции
и прекращает ее выполнение.
Пример.
Программа рассчитывает квадрат трех чисел и выводит на экран пары чисел
число-квадрат. Для расчета квадрата любого числа создается функция Kva с
одним входным параметром. В функции Kva значение входной переменной
умножается само на себя, а затем выдается оператором return. Функцию Kva
вызываем в методе main для каждого из трех чисел.
package ftest;
public class FunctionTest{
public static void main(String[] a){
System.out.print(“1 ”);
System.out.println(Kva(1));
System.out.print(“2 ”);
System.out.println(Kva(2));
System.out.print(“3 ”);

43
System.out.println(Kva(3));
}
public static int Kva(int x){
int z = x*x;
return z;
}
}
Результат.
11
24
39
Нужно отметить, что Kva работает независимо от того, какое число будет
подано на ее вход в качестве параметра, она является универсальной для всех
целых чисел. Ее задача – рассчитывать квадрат того числа, которое будет
подставлено ей как входной параметр. При первом вызове функции Kva на
вход поступает единица, т.е. единица помещается в х, Kva выполняет расчет,
результат которого записывается в z. Затем значение z выдается как результат
работы функции с помощью оператора return z, после чего работа передается
функции main, которая выводит его на экран, используя оператор
System.out.println(Kva(1));.
Пример.
Программа должна выдавать на консоль 15 строк, содержащих случайное
количество звездочек от 0 до 30. В программе необходимо реализовать
функцию PrintStars, которая бы выводила на экран только одну строку со
случайным количеством звездочек. Затем необходимо вызывать PrintStars 15
раз из функции main.
package MyPackage;
public class MyClass {
//=========================
public static void PrintStars(int x) {
for (int i = 0; i < x; i++) {
System.out.print("*");
}
System.out.println();
}
//=========================
public static void main(String[] arg) {
for (int i = 0; i < 15; i++) {
double z = 30 * Math.random();
int y = (int) Math.round(z);

44
PrintStars(y);
}
}
}
В функции main 15 раз выполняется цикл, на каждом шаге которого
выполняются следующие действия. В переменную z записывается случайное
число от 0 до 30, после чего оно округляется до целого и записывается в y.
Эту манипуляцию необходимо выполнять потому, что функция PrintStars
требует входящим параметром переменную целого типа (public static void
PrintStars(int x)). Затем значение y подается на вход функции PrintStars,
следовательно, подставляется во входной параметр x функции PrintStars. Таким
образом, ранее сгенерированное случайное число от 0 до 30 будет записано и
в переменной x. Внутри функции PrintStars выполняется цикл, количество
шагов которого равно х. т.е. х-раз выводится на экран звездочка, можно также
сказать, что цикл выводит на экран х звездочек. После выполнении цикла
происходит переход на следующую строку. Затем, по окончании PrintStars,
управление возвращается функции main для выполнения следующих шагов
цикла.
Пример.
e x  ex
Программа вычисляет элементы последовательностей y1  и
2
x 2  x3
y2  при условии, что x  1,2,...,10 . Следовательно, получается 10
4
элементов y1 и 10 элементов y 2 . Требуется посчитать сумму элементов y1 и
сумму элементов y2 и указать, какая сумма больше. Для каждой
последовательности нужно описать свою функцию, которая будет вычислять
один элемент для одного какого-то заданного х. Затем в цикле с десятью
шагами вызывать эти функции. Таким образом, в программе будет
реализовано две функции для расчета элементов последовательности и
функция main.
package sssssssss;
public class www{
//---------------------------------------------------------------------------------------------------
public static double y1(int x) {
double z = (Math.exp(x) + (Math.exp( -x))) / 2;
return z;
}

45
//---------------------------------------------------------------------------------------------------
public static double y2(int x) {
double z = (Math.pow(x, 2) + (Math.pow(x, 3))) / 4;
return z;
}
//---------------------------------------------------------------------------------------------------
public static void main(String[] args) {
double sum1 = 0;
double sum2 = 0;
for (int x = 1; x < 11; x++) {
double z = y1(x);
double q = y2(x);
sum1 += z;
sum2 += q;
}
System.out.println(sum2);
System.out.println(sum1);
if (sum1 > sum2) {
System.out.println("Sum1>Sum2");
}
if (sum1 < sum2) {
System.out.println("Sum1<Sum2");
}
if (sum1 == sum2) {
System.out.println("Sum1=Sum2");
}
}
}

5.2. Рекурсия

Функция называется рекурсивной, если во время ее обработки возникает


ее повторный вызов, либо непосредственно, либо косвенно, путем цепочки
вызовов других функций.
Прямой (непосредственной) рекурсией является вызов функции внутри
тела этой же функции.
int a()
{.....a().....}
Косвенной рекурсией является рекурсия, осуществляющая рекурсивный
вызов функции посредством цепочки вызова других функций. Все функции,
входящие в цепочку, тоже считаются рекурсивными.

46
Например:
a(){.....b().....}
b(){.....c().....}
c(){.....a().....}
Все функции a,b,c являются рекурсивными, так как при вызове одной из
них, осуществляется вызов других и самой себя.
Пример.
Необходимо написать программу, которая бы вычисляла сумму цифр в числе.
Затем в получившемся числе опять вычисляла сумму цифр. Эти действия
необходимо выполнять до тех пор, пока не останется число, состоящее из
одной цифры. Например, если ввести число 555, то, посчитав сумму цифр в
нем, получим 5+5+5=15. Так как получившееся число 15 состоит не из одной
цифры, то необходимо посчитать сумму цифр в нем, т.е. 1+5=6. Теперь было
получено число 6, состоящее из одной цифры, значит 6 - это и есть ответ.
package prg1;
import java.lang.*;
class Recursia {
//главная функция вызывает функцию Estimate
public static void main (String args[]) {
System.out.println(Estimate("555"));
}
// функция Estimate вызывает сама себя
String Estimate(String st){
long sum = 0;
for(int i=0;i<st.length();i++){
String c = st.substring(i,i+1);
sum+= Integer.parseInt(c);
}
String newSt = String.valueOf(sum);
if(newSt.length()>1)
newSt = Estimate(newSt);
return newSt;
}
}
Результат.
6
В программе главной в
функции вызывается метод
т.е. выполняется печать на экран результата
System.out.println(Estimate("555")),
выполнения функции Estimate при заданном в виде строки параметре 555.
Внутри функции Estimate, перебирая в цикле посимвольно строку st,

47
вычисляется сумма цифр в заданном числе. Результат помещается в
строковую переменную newSt командой String newSt = String.valueOf(sum); Затем
выполняется проверка if(newSt.length()>1), если количество знаков больше
одного, то вызываем эту же функцию Estimate, но с новым параметром,
который равен полученной сумме newSt = Estimate(newSt); Этот процесс может
повторяться многократно.

6. Объектно-ориентированное программирование
6.1. Введение в объектно-ориентированное программирование

Объектно-ориентированное программирование (ООП) в настоящее время


стало доминирующей парадигмой программирования, вытеснив
"структурные", процедурно-ориентированные способы программирования,
разработанные в начале 1970-х годов. Язык Java представляет собой
полностью объектно-ориентированный язык, и на нем невозможно
программировать в процедурном стиле.
Идея ООП состоит в том, что любая программа состоит из объектов,
обладающих определенными свойствами и возможностями выполнять
определенные операции.
Традиционное структурное программирование заключается в разработке
набора функций (или алгоритмов) для решения поставленной задачи.
Определив эти функции, программист должен задать подходящий способ
хранения данных.
Основной принцип, обеспечивший высокую производительность ООП,
заключается в том, что каждый объект предназначен для выполнения
определенных задач. Если перед объектом стоит задача, для решения которой
он не предназначен, у него должен быть доступ к другому объекту, который
может эту задачу решить. Затем первый объект просит второго решить эту
задачу. Это – обобщенный вариант вызова функций, применяемого в
процедурном программировании.
В частности, объект никогда не должен непосредственно
манипулировать внутренними данными другого объекта, а также
предоставлять другим объектам прямой доступ к своим данным. Все связи
между ними обеспечиваются с помощью вызовов методов. Инкапсуляция
(encapsulation) данных объекта максимально повышает возможность его
повторного использования, уменьшает их взаимозависимость и минимизирует
время отладки программы.

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

6.2. Основные термины объектно-ориентированного


программирования

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


использован в предыдущих примерах программ. Класс – это шаблон, или
проект, по которому будет сделан объект. Обычно класс сравнивают с формой
для выпечки печенья. Объект – это само печенье. Конструирование объекта на
основе некоторого класса называется созданием экземпляра (instance) этого
класса.
Как уже было показано, все коды, которые создаются в языке Java,
находятся внутри классов. Стандартная библиотека языка Java содержит
несколько тысяч классов, предназначенных для решения разных задач,
например, для создания пользовательского интерфейса, календарей и сетевого
программирования. Несмотря на это, программисты продолжают создавать
свои собственные классы на языке Java, чтобы описать объекты, характерные
для разрабатываемого приложения, а также адаптировать классы из
стандартной библиотеки для своих нужд.
Инкапсуляция (иногда называемая сокрытием данных) - это ключевое
понятие при работе с объектами. Формально инкапсуляция - это просто
объединение данных и операций над ними в одном пакете и сокрытие данных
от пользователя объекта. Данные в объекте называются полями экземпляра
(instance fields), а функции и процедуры, выполняющие операции над
данными, - его методами (methods). В указанном объекте, т.е. экземпляре
класса, поля экземпляра имеют определенные значения. Множество этих
значений называется текущим состоянием (state) объекта. Применение лю-
бого метода к какому-нибудь объекту может изменить его состояние.
Еще раз подчеркнем, что основной принцип инкапсуляции заключается в
запрещении прямого доступа к полям экземпляра данного класса методам
других классов. Программы должны взаимодействовать с данными объекта
только с помощью методов этого объекта. Это значит, что в классе можно

49
полностью изменить способ хранения данных, сохранив методы их
обработки, и при этом остальные объекты смогут работать с объектами этого
класса, как прежде.
Еще один принцип ООП облегчает разработку собственных классов в
языке Java: класс можно сконструировать на основе других классов. В этом
случае говорят, что вновь созданный класс расширяет класс, на основе
которого он построен. Язык Java, по существу, создан на основе "глобального
суперкласса", называемого, что вполне естественно, Object. Все остальные
объекты расширяют его.
Новый класс содержит все свойства и методы расширяемого класса, а
также новые методы и поля данных. Концепция расширения класса для
создания нового называется наследованием (inheritance).

6.3 Объекты

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


свойства объектов.
– Поведение (behavior) объекта - что с ним можно делать и какие методы
к нему можно применять.
– Состояние объекта - как этот объект реагирует на применение методов.
– Сущность (identity) объекта - чем данный объект отличается от других,
характеризующихся таким же поведением и состоянием.
Все объекты, являющиеся экземплярами одного и того же класса, ведут
себя одинаково. Поведение объекта определяется методами, которые можно
вызвать.
Далее, каждый объект сохраняет информацию о своем состоянии. Со
временем состояние объекта может измениться, однако спонтанно это
произойти не может. Состояние объекта может изменяться только в
результате вызовов методов. (Если состояние объекта изменилось вследствие
иных причин, значит, инкапсуляция нарушена.).
Однако состояние объекта не полностью описывает его, поскольку
каждый объект имеет свою собственную сущность. Например, в системе
обработки заказов два заказа могут отличаться друг от друга, даже если они
запрашивают одни и те же предметы. Заметим, что индивидуальные объекты,
представляющие собой экземпляры класса, всегда отличаются своей
сущностью и обычно отличаются своим состоянием.

50
Эти основные характеристики могут влиять друг на друга. Например,
состояние объекта может влиять на его поведение. (Если заказ "выполнен"
или "оплачен", объект может отказаться выполнить вызов метода,
требующего добавить или удалить предмет заказа. И наоборот, если заказ
"пуст", т.е. ни один предмет не был заказан, он не может быть выполнен.).
В традиционной процедурно-ориентированной программе выполнение
начинается сверху, с функции main. При разработке объектно-
ориентированной системы понятие "верха" не существует, и часто возникает
вопрос, с чего начинать. Ответ таков: "Сначала необходимо найти классы и
добавить методы в каждый класс".
Классы представляют собой аналоги имен существительных в описании
решаемой задачи, а методы - используемых при этом глаголов.
Например, при описании системы обработки заказов используются
следующие имена существительные:
– предмет;
– заказ;
– адрес доставки;
– оплата;
– счет.
Эти имена существительные соответствуют классам Item, Order и т.д.
Рассмотрим теперь глаголы. Предметы заказываются. Заказы
выполняются или отменяются. Оплата заказа осуществляется. Используя эти
глаголы, можно определить объект, выполняющий такие действия. Например,
если поступил новый заказ, то ответственность за его обработку должен нести
объект класса Order, поскольку именно в нем содержится информация о
способе хранения и видах заказываемых предметов. Следовательно, в классе
Order должен существовать метод add, получающий объект Item в качестве
параметра.

6.4 Отношения между классами

Между классами существуют три обычных отношения.


– Зависимость ("использует");
– Агрегирование ("содержит");
– Наследование ("является").
Отношение зависимости наиболее очевидное и распространенное.
Например, класс Order (заказ) использует класс Account(счет), поскольку

51
объекты класса Order должны иметь доступ к объектам класса Account, чтобы
проверить кредитоспособность заказчика. Однако класс Item (предмет) не
зависит от класса Account, так как объекты класса Item никогда не
интересуются состоянием счета заказчика. Следовательно, класс зависит от
другого класса, если его методы манипулируют объектами этого класса.
Необходимо стараться минимизировать количество взаимозависимых
классов. Если класс А не знает о существовании класса В, он тем более ничего
не знает о любых его изменениях! (Это значит, что любые изменения,
внесенные в класс В, не повлияют на класс А.) В терминах программного
обеспечения это означает минимизацию связей (couplings) между классами.
Отношение агрегирования (aggregation) означает, что класс А содержит
объекты класса В. Например, объект Order содержит объекты класса Item.
Наследование (inheritance) выражает отношение между конкретным и
более общим классом. Например, класс RushOrder(срочный заказ) является
производным от класса Order. Класс RushOrder имеет специальные методы
для обработки приоритетов и разные методы для вычисления стоимости
доставки, в то время как другие его методы, например, для заказа предмета и
выписывания счета, унаследованы им от класса Order. В частности, если класс
А расширяет класс В, то говорят, что класс А наследует методы класса В,
имея, кроме них, еще и дополнительные возможности.

7. Использование существующих классов


7.1. Объекты и объектные переменные

Для примера рассмотрим класс Math. Как было показано, методы класса
Math, например, метод Math.random, можно вызывать, ничего не зная о деталях
их реализации. Для вызова метода достаточно знать его имя и параметры
(если они есть).
Чтобы работать с объектами, их нужно сначала создать и задать их
исходное состояние. Затем к этим объектам можно применять методы.
В языке Java для создания новых экземпляров используются
конструкторы (constructors). Конструктор – это специальный метод,
предназначенный для создания и инициализации объектов. Рассмотрим
пример. Стандартная библиотека языка Java содержит класс Date. Его объекты
описывают моменты времени, например "December 31, 1999, 23:59:59 GMP".
Имя конструктора всегда совпадает с именем класса. Следовательно,
конструктор класса Date называется Date. Чтобы создать объект Date,

52
конструктор нужно соединить с оператором new, как показано в следующем
примере: new Date ().
Это выражение создает новый объект, который инициализируется
текущими датой и временем.
Обычно объект необходимо как-то идентифицировать, чтобы
использовать в дальнейшем. Для этого объект нужно присвоить переменной.
Date birthday = new Date();

birthday = Date

Рисунок 8 – Объектная переменная birthday, ссылающаяся на вновь


созданный объект

Между объектами и объектными переменными есть существенная


разница. Например, оператор
Date deadline; // Переменная Deadline не ссылается ни на один объект
определяет объектную переменную deadline, которая может ссылаться на
объекты типа Date. Важно понимать, что сама переменная deadline объектом не
является и, по существу, даже не ссылается ни на один объект, поэтому ни
один метод класса Date с помощью этой переменной вызывать пока нельзя.
Оператор
s = deadline. toString(); // Вызывать метод еще рано.
// Приведет к сообщению об ошибке.
Сначала переменную deadline нужно инициализировать. Существует две
возможности инициализации, переменную можно инициализировать вновь
созданным объектом:
deadline = new Date();
Кроме того, можно заставить переменную ссылаться на существующий
объект:
deadline = birthday;
Теперь обе переменные ссылаются на один и тот же объект.

53
birthday = Date

deadline =

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

Важно понимать, что объектная переменная фактически не содержит


никакого объекта. Она лишь ссылается на объект.
В языке Java значение любой объектной переменной представляет собой
ссылку на объект, размещенный где-то в другом месте. Оператор new также
возвращает ссылку. Например, оператор
Date deadline = new Date();
состоит из двух частей. Выражение new Date () создает объект типа Date, а его
значение представляет собой ссылку на этот вновь созданный объект.
Объектной переменной можно явно присвоить ссылку null, чтобы
отметить тот факт, что эта переменная пока не ссылается ни на один объект.
deadline = null;
if(deadline != null)
System.out.println(deadline);
Если применить этот метод к переменной, значение которой равно null,
то при выполнении программы возникнет ошибка.
birthday = null;
String s = birthday.toString(); // Ошибка!
Локальные объектные переменные не инициализируются автоматически
ссылкой null. Программист должен сам инициализировать ее, либо, вызвав
оператор new, либо присвоив ей значение null.

7.2. Класс GregorianCalendar из библиотеки языка Java

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


стандартной библиотеки языка Java. Экземпляр класса Date имеет состояние, а
именно: конкретный момент времени.
Хотя при использовании класса Date необязательно знать о формате даты,
отметим, что время представляется количеством миллисекунд
(положительным или отрицательным), отсчитанным от фиксированного

54
момента времени, так называемой эпохи (epoch), т.е. от 00:00:00 UTC, 1
января 1970 года.
Оказывается, однако, что класс Date не очень удобен для
манипулирования с датами. Разработчики библиотеки языка Java считали, что
представление даты, например "December 31, 1999, 23:59:59", является
совершенно произвольным и должно зависеть от календаря. Данное
конкретное представление подчиняется григорианскому календарю, самому
распространенному календарю в мире. Однако тот же самый момент времени
совершенно иначе представляется в китайском или еврейском лунном
календаре.
Разработчики библиотеки решили отделить вопросы, связанные с
отслеживанием моментов времени, от вопросов их представления. Таким
образом, стандартная библиотека языка Java содержит два отдельных класса:
класс Date, представляющий момент времени, и класс GregorianCalendar,
расширяющий более общий класс Calendar, описывающий свойства календаря
в целом. Теоретически можно расширить класс Calendar и реализовать
китайский лунный или марсианский календари. Однако в стандартной
библиотеке, кроме григорианского календаря, нет никакой другой
реализации.
Отделение измерения времени от календарей представляет собой
хорошее объектно-ориентированное решение.
Класс Date содержит лишь небольшое количество методов, позволяющих
сравнивать два момента времени. Например, методы before и after определяют,
предшествует один момент времени другому или следует за ним.
if (today.before(birthday))
System.out.println("Еще есть время купить подарок.");
Класс GregorianCalendar содержит гораздо больше методов, чем класс Date.
В частности, в нем есть несколько полезных конструкторов. Выражение new
GregorianCalendar() создает новый объект, представляющий дату и момент
времени, когда он был создан.
Можно создать объект, представляющий полночь указанной даты, год,
месяц и день:
new GregorianCalendar(1999, 11, 31);
Довольно странно, что количество месяцев отсчитывается от нуля. Таким
образом, число 11 означает декабрь. Для большей ясности можно
использовать константу Calendar.DECEMBER.
new GregorianCalendar(1999, Calendar.DECEMBER, 31)

55
Кроме того, можно задать время:
new GregorianCalendar(1999, Calendar.DECEMBER, 31, 23, 59, 59);
Разумеется, как обычно, созданный объект нужно присвоить объектной
переменной:
GregorianCalendar deadline = new GregorianCalendar(...);
Класс GregorianCalendar имеет инкапсулированные поля экземпляра, в
которых записана указанная дата. Не видя исходный текст, невозможно
определить, какое представление даты и времени использует этот класс.
Разумеется, это совершенно неважно. Важно лишь то, какие методы класс
предоставляет программисту.

7.3. Модифицирующие методы и методы доступа

Рассмотрим наиболее важные методы класса GregorianCalendar.


Календарь должен вычислять атрибуты указанного момента времени,
например, дату, день недели, месяц или год. Чтобы получить одно из этих
значений, можно использовать метод get из класса GregorianCalendar. Чтобы
выбрать желаемый атрибут, нужно передать методу константу, определенную
в классе Calendar, например, Calendar.MONTH или Calendar.DAY_OF_WEEK:
GregorianCalendar now = new GregorianCalendar();
int month = now.get(Calendar.MONTH);
int day = now.get(Calendar.DAY_OF_WEEK);
Состояние объекта можно изменить с помощью метода set:
deadline.set(Calendar.YEAR, 2001);
deadline(Calendar.MONTH, Calendar.APRIL);
deadline.set(Calendar.DAY, 15);
Существует удобный способ установить год, месяц и день с помощью
одного вызова:
deadline.set(2001, Calendar.APRIL, 15);
В заключение к заданной дате можно добавить количество дней, недель,
месяцев и т.д.
deadline.add(Calendar.MONTH, 3); // Отодвинуть момент deadline на 3 месяца.
Если добавить отрицательное число, календарь передвинется назад.
Между методом get с одной стороны и методами set и add с другой есть
принципиальная разница. Метод get только просматривает состояние объекта
и сообщает о нем, в том время как методы set и add модифицируют состояние
объекта. Методы, которые могут изменять поля экземпляра, называются

56
модифицирующими (mutators), a методы, которые могут лишь просматривать
поля экземпляра, не изменяя их, называются методами доступа (accessors).
В именах методов доступа принято использовать префикс get, а в именах
модифицирующих методов – префикс set. Например, класс GregorianCalendar
для получения и установки момента времени, представленного объектом,
имеет методы getTime и setTime соответственно.
Date time = calendar.getTime();
calendar.setTime(time);
Эти методы очень полезны для преобразований объектов класса
GregorianCalendarв объекты класса Date, и наоборот. Например, известны год,
месяц и день, и необходимо создать объект класса Date, поля которого были
бы заполнены этими значениями. Поскольку класс Date ничего не знает о
календарях, создадим сначала объект класса GregorianCalendar, а затем вызовем
метод getTime для получения даты.
И, наоборот, если нужно определить год, месяц или день, записанные в
объекте класса Date, создадим объект класса GregorianCalendar, установим
время, а затем вызовем метод get.
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(hireDay) ;
int year = calendar.get(Calendar.YEAR);
Пример.
Программа выводит на экран календарь текущего месяца. Текущий день
помечен звездочкой, причем программа знает, как вычислить дни недели.
package testprj;
import java.util.*;

public class CalendarTest{


public static void main(String[] args){
// Создаем объект d с текущей датой.
GregorianCalendar d = new GregorianCalendar();
int today = d.get(Calendar.DAY_OF_MONTH);
int month = d.get(Calendar.MONTH);
// Устанавливаем объект d на первую дату месяца.
d.set(Calendar.DAY_OF_MONTH, 1);
int weekday = d.get(Calendar.DAY_OF_WEEK);
// Выводим на печать заголовок таблицы.
System.out.println("Bc Пн Вт Ср Чт Пт Сб");
// Вставляем первую строку календаря.
for (int i = Calendar.SUNDAY; i < weekday; i++)
System.out.print(" ");

57
do {
// Выводим на печать день.
int day = d.get(Calendar.DAY_OF_MONTH);
if (day < 10)
System.out.print(" ");
System.out.print(day);
// Отметить текущий день звездочкой.
if (day == today)
System.out.print("* ");
else
System.out.print(" ");
// После каждой субботы начинаем новую строку.
if (weekday == Calendar.SATURDAY)
System.out.println ();
// Передвинуть объект d на новый день.
d.add(Calendar.DAY_OF_MONTH, 1) ;
weekday = d.get(Calendar.DAY_OF_WEEK);
}while(d.get(Calendar.MONTH) == month) ;
// Цикл завершается, когда объект d установлен
// на первый день следующего месяца.
// Выводим на экран последнюю строку.
if(weekday != Calendar.SUNDAY)
System.out.println();
}
}
Результат работы программы представлен на рисунке 10.

Рисунок 10 – Результат работы программы testprj

58
Рассмотрим ключевые пункты этой программы. Во-первых, создается
объект класса GregorianCalendar, инициализированный текущими датой и
временем. (На самом деле в данном приложении время нас не интересует.).
GregorianCalendar d = new GregorianCalendar();
Затем необходимо определить текущий день и месяц, дважды вызвав
метод get.
int today = d.get(Calendar.DAY_OF_MONTH);
int month = d.get(Calendar.MONTH);
После этого надо передать методу set объекта d параметр, задающий
первый день текущего месяца, и получить день недели, соответствующий
этой дате.
d.set(Calendar.DAY_OF_MONTH, 1) ;
int weekday = d.get(Calendar.DAY_OF_WEEK);
Переменная weekday полагается равной 1 (или Calendar.SUNDAY), если
первый день месяца - воскресенье, 2 (или Calendar.MONDAY) - если
понедельник, и т.д. Затем на экран выводится заголовок и пробелы,
выравнивающие первую строку календаря. Для каждого дня выводится на
экран пробел, если число меньше 10, затем-само число, а потом звездочка,
если число соответствует сегодняшнему дню. Каждое воскресенье выводится
с новой строки. Затем устанавливается объект d на следующий день:
d.add(Calendar.DAY_OF_MONTH, 1);
Когда же следует остановиться? Неизвестно, сколько в месяце дней: 31,
30, 29 или 28. Вместо этого необходимо продолжать итерации, пока объект d
остается в пределах текущего месяца.
do {
}while (d.get(Calendar.MONTH) == month) ;
Как только объект d перейдет на следующий месяц, программа завершит
свою работу.
Как видно, класс GregorianCalendar позволяет легко создавать программы
для работы с календарем, с учетом таких сложностей, как вычисление дней
недели и переменная продолжительность месяцев. Программист не обязан
ничего знать о том, как именно класс GregorianCalendar вычисляет месяцы и
дни недели. Нужно просто использовать методы get, set и add.

8. Создание собственных классов

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


Все эти классы состояли из одного-единственного метода main. Теперь
59
подошло время научиться создавать "рабочие" классы, необходимые в более
сложных приложениях. Обычно в этих классах нет метода main. Вместо этого
у них есть собственные поля и методы. Чтобы написать полностью
законченную программу, нужно объединить классы, один из которых имеет
метод main.
Простейшее определение класса в языке Java имеет следующий вид.
class ИмяКласса {
свойство1; (поле, некоторая глобальная переменная)
свойство2; (переменная)
конcтруктор1; (некоторая функция)
конструктор2; (функция)
метод1; (функция)
метод2; (функция)
}
Пример.
В рамках некоторой системы необходимо разработать набор классов для
хранения информации о треугольниках на плоскости. Известно, что
треугольник состоит из трех точек. Поэтому начнем разработку проекта с
создания класса Point, описывающего точку. Для этого в JBuilderX в проекте
необходимо создать новый класс. Необходимо помнить, что название файла
должно совпадать с названием класса.
package pname;
class Point {
float x;
float y;
Point() {
x=0;
y=0;
}
Point(float x, float y){
this.x=x;
this.y=y;
}
void setx(float x){
this.x=x;
}
void sety(float y){
this.y=y;
}
}

60
Точка на плоскости обладает двумя координатами. Поэтому объявляем
два свойства (переменных) типа float.
float x;
float y;
Описываем конструктор, функцию, которая имеет такое же название, как
и класс и выполняется во время инициализации экземпляра класса.
Point() {
x=0;
y=0;
}
Данный конструктор не имеет входящих параметров и выполняет
обнуление переменных x и y. Конструкторов в классе может быть несколько,
но все они должны отличаться списком входящих параметров.
Point(float x, float y){
this.x=x;
this.y=y;
}
Другой конструктор класса, который имеет два входящих параметра float
x, float y. Он получает пару чисел с плавающей запятой x и y и записывает ее в
соответствующие переменные this.x и this.y. Ключевое this слово означает, что
обращение происходит к глобальной переменной класса, описанной как
свойство класса, а не к входящему параметру функции. Другими словами, this
помогает различить переменную объявленную как свойство класса от
переменной с таким же названием в функции.
void setx(float x){
this.x=x;
}
Метод setx реализует инкапсуляцию, записывает новое значение в
свойство класса x, из входящей переменной x. Аналогичная функция
реализуется и для второй координаты.
void sety(float y){
this.y=y;
}
Далее необходимо создать новый класс для описания свойств и методов
треугольника. Назовем его T3angl. Для в проект добавляем новый класс, т.е. в
проекте создается новый файл T3angl.java.

61
package pname;
import java.lang.*;
class T3angl {
Point p1, p2, p3;
T3angl() {
p1 = new Point(0, 0);
p2 = new Point(0, 0);
p3 = new Point(0, 0);
}
void setp1(Point p) {
this.p1 = p;
}
void setp2(Point g) {
this.p2 = g;
}
void setp3(Point e) {
this.p3 = e;
}
float Dealta(Point S, Point H) {
float D = 0;
D = (float) Math.sqrt( (float) (Math.pow( (S.x - H.x), 2) +
Math.pow( (S.y - H.y), 2)));
return D;
}
float EstimateP() {
float P = 0;
P=Dealta(p1,p2)+Dealta(p2,p3)+Dealta(p3,p1);
return P;
}
float EstimateS() {
float S = 0;
S=(float)Math.sqrt(( EstimateP()/(float)2.0)*( EstimateP()/(float)2.0-Dealta(p1,p2))*
( EstimateP()/(float)2.0-Dealta(p2,p3))*
( EstimateP()/(float)2.0-Dealta(p3,p1)));
return S;
}
}
Сначала объявляется три переменных типа Point. Они будут хранить
информацию о точках треугольника.
Point p1, p2, p3;
Далее опишем конструктор класса.

62
T3angl() {
p1 = new Point(0, 0);
p2 = new Point(0, 0);
p3 = new Point(0, 0);
}
Конструктор T3angl вызывает для каждой точки конструктор класса Point
с двумя входящими параметрами. Оператор new выделяет место в памяти
для хранения точки, а конструктор Point(0, 0) записывает в свойства x и y
значение 0. Таким образом, после того, как отработает функция T3angl() все
три точки будет иметь координаты (0,0).
void setp1(Point p) {
this.p1 = p;
}
Данная функция записывает значение входящего параметра p в
переменную класса p1. Опишем подобную функцию для каждой точки
треугольника. Назовем их setp2 и setp3 соответственно.
Добавим некоторые полезные методы для треугольника. Например,
расчет расстояния между двумя любыми точками.
float Dealta(Point S, Point H) {
float D = 0;
D = (float) Math.sqrt( (float) (Math.pow( (S.x - H.x), 2) +
Math.pow( (S.y - H.y), 2)));
return D;
}
Если подставить в такую функцию две точки, вершины треугольника
(переменные типа Point), то она вычислит длину стороны, соединяющей эти
точки.
Далее, опишем функцию, вычисляющую периметр треугольника.
float EstimateP() {
float P = 0;
P=Dealta(p1,p2)+Dealta(p2,p3)+Dealta(p3,p1);
return P;
}
Вызвав функцию Dealta с входными параметрами p1 и p2, вычислим длину
одной стороны. Dealta(p2,p3) – вычисляет длину второй стороны, а Dealta(p3,p1) –
третьей. Сложив результаты, получим периметр P.
И, наконец, разработаем функцию для нахождения площади
треугольника EstimateS(). В реализации функции используется формула Герона
для нахождения площади треугольника по трем сторонам.

63
float EstimateS() {
float S = 0;
S=(float)Math.sqrt(( EstimateP()/(float)2.0)*( EstimateP()/(float)2.0-Dealta(p1,p2))*
( EstimateP()/(float)2.0-Dealta(p2,p3))*
( EstimateP()/(float)2.0-Dealta(p3,p1)));
return S;
}
Теперь, чтобы программа запускалась, необходимо реализовать класс,
обладающий функцией main. Назовем его MainClass. Внутри функции main
зададим два треугольника и попробуем выяснить, площадь какого из них
больше.
package pname;
public class MainClass {
public static void main(String[] args) {
T3angl TR1 = new T3angl();
Point M = new Point( (float) 2, (float) 3);
TR1.setp1(M);
Point N = new Point( (float) 4, (float) 5);
TR1.setp2(N);
Point F = new Point( (float) 1, (float) 6);
TR1.setp3(F);
T3angl TR2 = new T3angl();
Point A = new Point( (float) 2, (float) 3.0);
TR2.setp1(A);
Point B = new Point( (float) 4.7, (float) 5.7);
TR2.setp2(B);
Point C = new Point( (float) 1.2, (float) 6.5);
TR2.setp3(C);
if (TR1.EstimateS() > TR2.EstimateS()) {
System.out.println("TR1>TR2");
} else {
System.out.println("TR2>=TR1");
}
}
}
Опишем работу главной функции.
T3angl TR1 = new T3angl();
Создается экземпляр класса T3angl. Переменная получает название TR1.
Оператор new выделяет место в памяти для экземпляра класса T3angl, затем
вызывается пустой конструктор T3angl() Если посмотреть реализацию
конструктора T3angl(), то внутри него три раза вызывается конструктор класса
64
точек Point(0,0), задающий точке координаты (0,0). Таким образом, выполнение
одной строки иницализирует треугольник, у которого все три точки находятся
в начале координат.
Создадим какую-то точку с координатами (2,3).
Point M = new Point( (float) 2, (float) 3);
Запишем эту точку в треугольник, используя метод setp1.
TR1.setp1(M);
Таким образом, у треугольника TR1 в свойстве p1 будет записана точка с
координатами (2,3). Или, другими словами, у свойства p1 в полях x и y будут
храниться значения 2 и 3 соответственно.
Подобным образом заполним две другие точки треугольника.
Point N = new Point( (float) 4, (float) 5);
TR1.setp2(N);
Point F = new Point( (float) 1, (float) 6);
TR1.setp3(F);
Заполним параметры второго треугольника.
T3angl TR2 = new T3angl();
Point A = new Point( (float) 2, (float) 3.0);
TR2.setp1(A);
Point B = new Point( (float) 4.7, (float) 5.7);
TR2.setp2(B);
Point C = new Point( (float) 1.2, (float) 6.5);
TR2.setp3(C);
Затем, необходимо определить, какой из треугольников занимает
большую площадь, вызвав у обоих функцию EstimateS().
if (TR1.EstimateS() > TR2.EstimateS()) {
System.out.println("TR1>TR2");
} else {
System.out.println("TR2>=TR1");
}
Таким образом, был рассмотрен пример разработки объектно-
ориентированного приложения.
Рассмотрим следующий пример.
Пример.
Программа должна выводить на экран список студентов группы, указывая в
строчку через пробел фамилию, год рождения, три оценки и средний бал.
Необходимо разработать систему классов для реализации программы. Для
хранения информации о студенте построим класс Stud.

65
package uni;
public class Stud {
String FIO;
int year, m1, m2, m3;
Stud() {
FIO = " ";
year = m1 = m2 = m3 = 0;
}
Stud(String FIO) {
this.FIO = FIO;
year = m1 = m2 = m3 = 0;
}
Stud(String FIO, int year, int m1, int m2, int m3) {
this.FIO = FIO;
this.m1 = m1;
this.m2 = m2;
this.m3 = m3;
this.year = year;
}
float Sredn() {
int Sum = m1 + m2 + m3;
return (float) Sum / 3;
}
void PrintSt() {
System.out.println(FIO + "\t" + year + "\t" +
m1 + " " + m2 + " " + m3 + "\t" + Sredn());
}
void setMarks(int m1, int m2, int m3) {
this.m1 = m1;
this.m2 = m2;
this.m3 = m3;
}
}
Рассмотрим подробнее реализацию этого класса.
String FIO;
int year, m1, m2, m3;
Объявляем поля (методы) класса – фамилию, год рождения и три оценки
соответственно.
Stud() {
FIO = " ";
year = m1 = m2 = m3 = 0;
}

66
Данный пустой конструктор ницализирует поля по умолчанию. В FIO
записывает пробел, а значение года и оценок делает равным 0.
Stud(String FIO) {
this.FIO = FIO;
year = m1 = m2 = m3 = 0;
}
Этот конструктор разработан для инициализации студента, зная только
его фамилию. Здесь переменная класса FIO получает значение входного
параметра функции FIO. Все остальные переменные класса обнуляются.
И, наконец, конструктор для инициализации всех необходимых полей
студента.
Stud(String FIO, int year, int m1, int m2, int m3) {
this.FIO = FIO;
this.m1 = m1;
this.m2 = m2;
this.m3 = m3;
this.year = year;
}
Далее напишем функцию для расчета среднего бала студента.
float Sredn() {
int Sum = m1 + m2 + m3;
return (float) Sum / 3;
}
Эта функция не имеет входных параметров, а использует глобальные
переменные класса Stud – m1, m2 и m3. Т.е. эта функция рассчитывает средний
бал для конкретного студента, фамилия которого равна FIO.
void PrintSt() {
System.out.println(FIO + "\t" + year + "\t" +
m1 + " " + m2 + " " + m3 + "\t" + Sredn());
}
Функция выводит на консоль информацию об одном студенте, указывает
в строчку его фамилию FIO, год рождения year, три оценки m1, m2, m3 и средний
бал, который рассчитывает функция Sredn().
void setMarks(int m1, int m2, int m3) {
this.m1 = m1;
this.m2 = m2;
this.m3 = m3;
}

67
Вызов этой функции произведет запись в поля оценок тех значений,
которые подаются на ее вход. Ее можно использовать во время корректировки
информации о студенте.
Разобравшись со студентом, перейдем к реализации класса,
описывающего группу студентов. Известно, что группа – это класс,
содержащий массив студентов, обладающий названием и некоторыми
полезными методами.
package uni;
import java.lang.*;
public class Group {
String grName;
Stud[]Student;
Group() {
grName=" ";
Student=new Stud[5];
for(int i=0;i<5;i++){
Student[i]=new Stud();
}
}
void setName(String grName){
this.grName=grName;
}
void printGR1(){
System.out.println(grName);
for (int i = 0; i < Student.length; i++) {
System.out.print(Student[i].FIO+
"\t"+Student[i].year+
"\t"+Student[i].m1+
" "+Student[i].m2+
" "+Student[i].m3+" ");
System.out.println(Student[i].Sredn());
}
}
void printGR2(){
System.out.print(grName);
for(int i=0;i < Student.length; i++){
Student[i].PrintSt();
}
}
}

68
Здесь, группе зададим название и укажем компилятору, что студенты
хранятся в виде массива неопределенной длины.
String grName;
Stud[]Student;
Далее опишем пустой конструктор.
Group() {
grName=" ";
Student=new Stud[5];
for(int i=0;i<5;i++){
Student[i]=new Stud();
}
В нем по умолчанию присваивается имени группы grName пустая строка.
Student=new Stud[5];
Выделяется место под массив из пяти элементов.
for(int i=0;i<5;i++){
Student[i]=new Stud();
В цикле, для всех пяти студентов вызывается конструктор Stud(),
выполняющий инициализацию по умолчанию.
void setName(String grName){
this.grName=grName;
}
Функция setName задает новое значение параметру grName.
Далее опишем функцию печати списка группы. Она реализована двумя
способами. Рассмотрим первый способ – функцию printGR1().
void printGR1(){
System.out.println(grName);
for (int i = 0; i < Student.length; i++) {
System.out.print(Student[i].FIO+
"\t"+Student[i].year+
"\t"+Student[i].m1+
" "+Student[i].m2+
" "+Student[i].m3+" ");
System.out.println(Student[i].Sredn());
}
Сначала в отдельной строке выводится название группы.
System.out.println(grName);
Затем, в цикле в отдельных строках печатается информация о каждом
студенте.
Здесь Student.length – длина массива Student.

69
Student[i].year – обращение к студенту под номером i и к его полю year.
Вообще, для того, чтобы вытянуть значение некоторого поля объекта,
необходимо указать название переменной – экземпляра класса и через точку
задать название поля. Аналогично обращаемся к функции Student[i].Sredn(),
которая считает средний бал для студента под номером i.
Следующий способ реализации функции печати показывает printGR2().
void printGR2(){
System.out.print(grName);
for(int i=0;i < Student.length; i++){
Student[i].PrintSt();
}
}
Здесь, обращение к полям экземпляра класса Stud не происходит, но для
каждого студента вызывается своя функция печати Student[i].PrintSt().
Далее реализуем главный класс MainUniclass с функцией main.
package uni;
public class MainUniclass {
public static void main(String[] St) {
Group G = new Group();
G.setName("KIT-76");
G.Student[0].FIO = "Иванов И.И.";
G.Student[0].year = 1990;
G.Student[0].setMarks(2, 3, 4);
G.Student[1].FIO = "Петров П.П.";
G.Student[1].year = 1989;
G.Student[1].setMarks(3, 3, 4);
G.Student[2].FIO = "Сидоров С.С.";
G.Student[2].year = 1988;
G.Student[2].setMarks(4, 4, 4);
G.Student[3].FIO = "Никитин Н.Н.";
G.Student[3].year = 1991;
G.Student[3].setMarks(2, 3, 2);
G.Student[4].FIO = "Сергеев С.С.";
G.Student[4].year = 1990;
G.Student[4].setMarks(2, 2, 4);
G.printGR1();
G.printGR2();
}
}
Сначала зададим переменную – экземпляр класса Group.
Group G = new Group();

70
По умолчанию отработал пустой конструктор, который иницализирует
название группы grName пустой строкой и выделяет место под массив из пяти
элементов. В свою очередь, конструктор каждого студента инициализирует
экземпляр класса Stud нулевыми значениями оценок и года рождения.
Обратимся к студенту, который хранится в массиве по номером 0 и
заполним его поля.
G.Student[0].FIO = "Иванов И.И.";
G.Student[0].year = 1990;
G.Student[0].setMarks(2, 3, 4);
Здесь, указывается экземпляр класса Group под названием G. Далее, через
точку указываем поле класса Group, в котором хранятся студенты. В
описанном классе это – массив Student, который, в свою очередь, является
массивом экземпляров класса Stud. Т.к. Student – массив, то необходимо указать
номер ячейки. Таким образом, перечисляя через точки поля, достигается
конкретный студент, поля которого заполняются напрямую. Для того чтобы
задать оценки, используем функцию setMarks(2, 3, 4).
Подобным образом заполняется информация о других студентах.
Вызовем функции печати для сравнения
G.printGR1();
G.printGR2();

9. Использование пакетов

Язык Java позволяет объединять классы в коллекции, называемые


пакетами (packages). Пакеты облегчают организацию работы и позволяют
отделить собственную работу от классов, разработанных другими
программистами.
Стандартная библиотека языка Java распространяется в виде большого
количества пакетов, включая пакеты java.lang, java.util, java.net и др.
Стандартные пакеты языка Java являются иерархическими. Подобно
каталогам на диске, пакеты могут быть вложены один в другой. Все
стандартные пакеты включены в иерархии пакетов java и javax.
В основном, пакеты используются для обеспечения уникальности имен
классов. Допустим, двух программистов осенила блестящая идея создать

71
класс Student. Если оба класса будут находиться в разных пакетах, конфликт
не возникнет.
Единственная цель вложенных пакетов – гарантия уникальности имен. С
точки зрения компилятора между вложенными пакетами нет абсолютно
никакой связи. Например, пакеты java.util и java.util.jar никак не связаны друг с
другом. Каждый из них представляет собой независимую коллекцию классов.
Класс может использовать все классы из собственного пакета и все
открытые классы из других пакетов.
Доступ к открытым классам из других пакетов можно получить двумя
путями. Во-первых, можно просто добавить полное имя пакета перед именем
каждого класса. Например,
java.util.Date today = new java.util.Dat e();
Очевидно, что этот способ слишком утомителен. Более простой и
распространенный способ – использовать ключевое слово import. Оператор
import допускает более короткие имена для ссылок на классы, находящиеся в
пакете. В этом случае не нужно указывать полные имена классов.
Можно импортировать как один конкретный класс, так и весь пакет.
Операторы import следует поместить в начало исходного файла (но
после всех операторов package). Например, все классы из пакета java.util
можно импортировать с помощью оператора
import java.util.*;
Затем можно использовать следующий оператор, не указывая префикса,
задающего имя пакета.
Date today = new Date () ;
Можно также импортировать отдельный класс из пакета.
import java.util.Date;
Импортировать все классы из пакета проще. Негативного влияния на
размер кода это не оказывает, поэтому нет никаких причин не делать этого.
Однако следует заметить, что оператор import со звездочкой * можно
применять для импортирования только одного пакета. Нельзя использовать
обозначение import java.* или import java.*.*, чтобы импортировать все пакеты,
имена которых содержат префикс java.
Импортировать можно только классы, но не объекты. Например,
невозможно импортировать объект System.out.

72
В большинстве случаев импортируется весь пакет, независимо от его
размера. Единственный вариант, при котором на пакет следует обратить
особое внимание – конфликт имен. Например, и пакет java.util, и пакет java.sql
содержат класс Date. Допустим, разрабатывается программа, импортирующая
оба этих пакета.
import java.util.*;
import java.sql.*;
Если теперь попытаться использовать класс Date, возникнет ошибка
компиляции:
Date today; // ОШИБКА - java.util.Date или java.sql.date?
Компилятор не может определить, какой класс Date нужен. Решить эту
проблему можно, добавив конкретный оператор import:
import java.util.*;
import java.sql.*;
import java.util.Date;
А если вам на самом деле нужны оба класса Date? Для этого нужно
указывать полное имя пакета для каждого имени класса.
Java.util.Date deadline = new Java.util.Date();
java.sql.Date today = new Java.sql.Date();
Обнаружение классов в пакетах является задачей компилятора. Байт-
коды в файлах классов всегда используют полные имена пакетов для ссылок
на другие классы.
Чтобы поместить класс в пакет, нужно указать имя пакета в начале
исходного файла перед кодом, определяющим класс. Например, файл
Stud.java начинается следующими строками.
package uni;
public class Stud{
………..
……….
}
Пакеты следует помещать в подкаталог, имя которого соответствует
полному имени пакета.

73
Список литературы

1. Хорстманн К.С., Корнелл Г. Библиотека профессионала. Java 2. Том 1.


Основы.: Пер. с англ. – М.: Издательский дом «Вильямс», 2003. – 848с.
2. Хорстманн К.С., Корнелл Г. Библиотека профессионала. Java 2. Том 2.
Тонкости программирования.: Пер. с англ. – М.: Издательский дом
«Вильямс», 2002. – 1120с.
3. Технология программирования на Java 2: Книга 1. Графика, JavaBeans,
интерфейс пользователя. Пер. с англ. – М.: ООО «Бином-Пресс», 2003.
– 560с.
4. Флэнаган Д. Справочник, 4-е издание – СПб: Символ-плюс, 2004. –
1040с.
5. www.javagu.ru
6. www.sun.com

74
Содержание

Вступление……………………………………………………………… 3
1. Первые шаги в программировании …………………………...… 4
1.1. Первая программа на Java…………………………………….. 4
1.2. Переменные и типы данных…………………………………... 6
1.3. Присваивание………………………………………………….. 8
1.4. Порядок выполнения простых математических операций…. 9
1.5. Преобразования числовых типов…………………………… 10
1.6. Приведение числовых типов………………………………...... 11
1.7. Математические операции и вычисления……………………. 12
2. Логические ветвления программ………………………………… 14
2.1. Блоки операторов…………………………………………….... 14
2.2. Оператор ветвления if…………………………………………. 15
2.3. Оператор варианта switch……………………………………... 20
2.4. Циклы…………………………………………………………… 21
3. Массивы……………………………………………………………… 26
3.1. Одномерные массивы………………………………………… 26
3.2. Двумерные массивы…………………………………………... 30
4. Строковые типы данных в java…………………………………... 34
4.1. Строки………………………………………………………….. 34
4.2. Подстроки……………………………………………………… 35
4.3. Редактирование строки……………………………………….. 35
4.4. Проверка строк на равенство…………………………………. 36
4.5. Считывание ввода……………………………………………... 39
5. Функции……………………………………………………………… 41
5.1. Основы использования функций в JAVA……………………. 41
5.2. Рекурсия………………………………………………………... 46
6. Объектно-ориентированное программирование……………….. 48
6.1. Введение в объектно-ориентированное программирование... 48
6.2. Основные термины объектно-ориентированного…………… 49
6.3. Объекты………………………………………………………… 50
6.4. Отношения между классами…………………………………... 51
7. Использование существующих классов…………………………. 52
7.1. Объекты и объектные переменные…………………………… 52
7.2. Класс GregorianCalendar из библиотеки языка Java…………. 54
7.3. Модифицирующие методы и методы доступа………………. 56
8. Создание собственных классов…………………………………… 59
9. Использование пакетов……………………………………………. 71
Список литературы……………………………………………..……... 74

75
Навчальне видання

ПУСТОВОЙТОВ Павло Євгенович

Програмування на JAVA 2

Навчальний посібник
з дисципліни
«Обчислювальна техніка та програмування»

Для студентів спеціальності 6.091200 - Відео-, аудіо- та кінотехніка

Російською мовою

Роботу рекомендував до видання проф. Дмитрієнко В.Д.

В авторський редакції

План 2007 p., поз.1.

Підп. до друку __.__.2007. Формат 60x84 1/16. Папір офсетний.


Друк - ризографія. Гарнітура Times New Roman. Ум. друк. арк. 5,0.
Обл.-вид. арк. 5,0. Наклад 100 прим. Зам. № 25. Ціна договірна.
___________________________________________________________________
Видавничий центр НТУ «ХПІ». Свідоцтво ДК №116 від 10.07.2000 р.
61002, Харків, вул. Фрунзе, 21.
___________________________________________________________________
ЧП Ляпін, Харків, вул. Пушкінська 74, Торговий центр 74
__________________________________________________________________

76

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