Глава 1
ВВЕДЕНИЕ В ООП И КЛАССЫ
Каждый дурак может написать программу, которую
может понять компьютер. Хороший программист пишет
программу, которую может понять человек.
Мартин Фаулер
Основные понятия ООП
Java
является объектно-ориентированным языком программирования, вслед-
ствие чего предварительно будут приведены основные парадигмы ООП.
В связи с проникновением компьютеров во все сферы социума программ-
ные системы становятся более простыми для пользователя и сложными по вну-
тренней архитектуре. Программирование стало делом команды, где маленьким
проектом считается тот, который выполняет команда из 5–10 специалистов
за время от полугода до года.
Основным способом борьбы со сложностью программных продуктов стало
объектно-ориентированное программирование (ООП), являющееся в настоя-
щее время наиболее популярной парадигмой.
ООП — методология программирования, основанная на представлении
программного продукта в виде совокупности объектов, каждый из которых яв-
ляется экземпляром конкретного класса. ООП использует в качестве базовых
элементов взаимодействие объектов.
Объект — именнованная модель реальной сущности, обладающая конкрет-
ными значениями свойств и проявляющая свое поведение.
В применении к объектно-ориентированным языкам программирования по-
нятия объекта и класса конкретизируются.
Объект — обладающий именем набор данных (полей и свойств объекта),
физически на ходящихся в памяти компьютера, и методов, имеющих доступ
к ним. Имя исполь зуется для работы с полями и методами объекта.
Любой объект относится к определенному классу. В классе дается обобщен-
ное описание некоторого набора родственных объектов.
Объект — конкретный экземпляр класса.
В качестве примера можно привести абстракцию дома или его описание (класс)
и реальный дом (экземпляр класса или объект). Объект соответствует логической
модели дома, представляющей совокупное описание всех физических объектов.
ВВЕДЕНИЕ В ООП И КЛАССЫ
13
Класс принято обозначать в виде прямоугольника, разделенного на три части.
В верхний прямоугольник помещается имя класса, в средний — набор по-
лей с именами, типами, свойствами класса, и в нижний — список методов, их
параметров и возвращаемых значений.
Реальный объект должен иметь конкретные значения всех полей, например:
id=35, masonry="brick", numberFloors=2, numberWindows=7.
Объектно-ориентированное программирование основано на принципах:
— инкапсуляции;
— наследования;
— полиморфизма, в частности, «позднего связывания».
Инкапсуляция (encapsulation) — принцип, объединяющий данные и код, ма-
нипулирующий этими данными, а также защищающий данные от прямого
внешнего доступа и неправильного использования. Другими словами, доступ
к данным класса возможен только посредством методов этого же класса.
Наследование (inheritance) — процесс, посредством которого один класс
может наследовать свойства другого класса и добавлять к ним свойства и мето-
ды, характерные только для него.
Наследование бывает двух видов:
одиночное наследование — подкласс (производный класс) имеет один
и только один суперкласс (предок);
множественное наследование — класс может иметь любое количество
предков (в Java запрещено).
Полиморфизм (polymorphism) — механизм, использующий одно и то же
имя метода для решения похожих, но несколько отличающихся задач в раз-
личных объектах при наследовании из одного суперкласса. Целью полимор-
физма является использование одного имени при выполнении общих для су-
перкласса и подклассов действий.
Механизм «позднего связывания» в процессе выполнения программы опре-
деляет принадлежность объекта конкретному классу и производит вызов метода,
Рис. 2.1.
Описание класса (абстракция) и реальный объект
Рис. 2.2.
Графическое
изображение класса
ОСНОВЫ JAVA
14
относящегося к классу, объект которого был использован. Механизм «позднего
связывания» позволяет определять версию полиморфного (виртуального) мето-
да во время выполнения программы. Другими словами, иногда невозможно
на этапе компиляции определить, какая версия переопределенного метода бу-
дет вызвана на этапе выполнения программы.
Краеугольным камнем наследования и полиморфизма предстает следующая
парадигма: «объект подкласса может использоваться всюду, где использу-
ется объект суперкласса». То есть при добавлении к иерархии классов нового
подкласса существующий код с экземпляром нового подкласса будет работать
точно так же, как и со всеми другими экземплярами классов в иерархии.
При вызове метода сначала он ищется в самом классе. Если метод сущест-
вует, то он вызывается. Если же метод в текущем классе отсутствует, то обра-
щение происходит к родительскому классу и вызываемый метод ищется в этом
классе. Если поиск неудачен, то он продолжается вверх по иерархическому де-
реву вплоть до корня (верхнего класса Object) иерархии.
Язык Java
Объектно-ориентированный язык Java, разработанный в компании Sun
Microsystems в 1995 году для оживления графики на стороне клиента с помо-
щью апплетов, в настоящее время используется для создания переносимых
на различные платформы и опера ционные системы программ. Язык Java на-
шел широкое применение в Интернет-приложениях, добавив на статические
и клиентские веб-страницы динамическую графику, улучшив интерфейсы
и реализовав вычислительные возможности. Но объектно-ориентированная
парадигма и кроссплатформенность привели к тому, что уже буквально через
несколько лет после создания язык практически покинул клиентские страницы
и перебрался на серверы. На стороне клиента его место заняли языки JavaScript,
Adobe Flash и проч.
При создании язык Java предполагался более простым, чем его синтаксиче-
ский предок С++. Сегодня с появлением новых версий возможности языка
Java
существенно расширились и во многом перекрывают функциональность
С++. Java уже не уступает по сложности предшественникам и называть его
простым нельзя.
Отсутствие указателей (наиболее опасного средства языка С++) нельзя
считать сужением возможностей, а тем более — недостатком, это просто тре-
бование безопасности. Возможность работы с произвольными адресами памя-
ти через безтиповые указатели позволяет игнорировать защиту памяти.
Отсутствие в Java множественного наследования легко заменяется на более
понятные конструкции с применением интерфейсов.
Системная библиотека классов языка Java содержит классы и пакеты, реа-
лизующие и расширяющие базовые возможности языка, а также сетевые
ВВЕДЕНИЕ В ООП И КЛАССЫ
15
средства, взаимодействие с базами данных, графические интерфейсы и многое
другое. Методы классов, включенных в эти библиотеки, вызываются JVM (Java
Virtual Machine) во время интерпретации программы.
В Java все объекты программы расположены в динамической памяти —
куче данных (heap) и доступны по объектным ссылкам, которые, в свою оче-
редь, хранятся в стеке (stack). Это решение исключило непосредственный до-
ступ к памяти, но усложнило работу с элементами массивов и сделало ее менее
эффективной по сравнению с программами на C++. В свою очередь, в Java
предложен усовершенствованный механизм работы с коллекциями, реализую-
щими основные динамические структуры данных. Необходимо отметить, что
объектная ссылка языка Java содержат информацию о классе объекта, на кото-
рый она ссылается, так что объектная ссылка — это не указатель, а дескриптор
(описание) объекта. Наличие дескрипторов позволяет JVM выполнять провер-
ку совместимости типов на фазе интерпретации кода, генерируя исключение
в случае ошибки. В Java изменена концепция организации динамического рас-
пределения памяти: отсутствуют способы программного освобождения дина-
мически выделенной памяти. Вместо этого реализована система автомати-
ческого освобождения памяти (сборщик мусора), выделенной с помощью опе-
ратора new. Программист может только рекомендовать системе освободить
выделенную динамическую память.
В отличие от C++, Java не поддерживает множественное наследование, пе-
регрузку операторов, беззнаковые целые, прямое индексирование памяти и, как
следствие, указатели. В Java существуют конструкторы, но отсутствуют деструк-
торы (применяется автоматическая сборка мусора), не используется оператор
goto и слово const, хотя они являются зарезервированными словами языка.
Ключевые и зарезервированные слова языка Java:
abstract
сontinue
for
new
switch
assert
default
goto*
package
synchronized
boolean
do
if
private
this
break
double
implements
protected
throw
byte
else
import
public
throws
case
enum
instanceof
return
transient
catch
extends
int
short
try
char
final
interface
static
void
class
finally
long
strictfp
volatile
const*
f
loat
n
ative
super
while
Кроме ключевых слов в Java существуют три литерала: null, true, false, не от-
носящиеся к ключевым и зарезервированным словам.
ОСНОВЫ JAVA
16
Простое приложение
Изучение любого языка программирования удобно начинать с программы
передачи символьного сообщения на консоль.
// # 1 # простое линейное приложение # OracleSlogan.java
public
class OracleSlogan {
public static void main(String[ ] args) {
// вывод строки
System.out.println("Enabling the Information Age");
}
}
Но уже в этом коде заложен фундамент будущих архитектурных ошибок.
Пусть представленный выше класс является первым из множества классов си-
стемы, которые будут созданы в процессе разработки небольшой системы пе-
редачи некоторых сообщений, состоящей, например, из двух–трех десятков
классов. Строка
System.out.println("Enabling the Information Age");
может встречаться в коде этих классов многократно. Пусть в процессе тестиро-
вания или внедрения системы окажется, что фразу необходимо заменить
на другую, например, в конце поставить восклицательный знак. Для этого про-
граммисту придется обыскивать весь код, искать места, где встречается ука-
занная фраза, и заменять ее новой. Это по меньшей мере, неудобно. Что делать
если таких классов — не пара десятков, а несколько сотен? Во избежание подобных
проблем сообщение лучше хранить в отдельном методе или константе (а еще
лучше — в файле) и при необходимости вызывать его. Тогда изменение текста
сообщения приведет к локальному изменению одной-единственной строки
кода. В следующем примере этот код будет переписан с использованием двух
классов, реализованных на основе простейшего применения объектно-ориен-
тированного программирования:
/* # 2 # простое объектно-ориентированное приложение # FirstProgram.java */
package
by.bsu.simple;
public
class FirstProgram {
public static void main(String [ ] args) {
// объявление и создание объекта firstObject
SloganAction firstObject = new SloganAction();
// вызов метода, содержащего вывод строки
firstObject.printSlogan();
}
}
ВВЕДЕНИЕ В ООП И КЛАССЫ
17
// # 3 # простой класс # SloganAction
class
SloganAction {
void
printSlogan() { // определение метода
// вывод строки
System. out.println("Enabling the Information Age");
}
}
Здесь класс FirstProgram используется для того, чтобы определить метод
main(), который вызывается автоматически интерпретатором Java и может назы-
ваться контроллером этого примитивного приложения. Метод main() получает
в качестве параметра аргументы командной строки String[]args, представляю-
щие массив строк, и является открытым ( public) членом класса. Это означает,
что метод main() может быть виден и доступен любому классу. Ключевое слово
static объявляет методы и переменные класса, используемые при работе с клас-
сом в целом, а не только с объектом класса. Символы верхнего и нижнего реги-
стров здесь различаются. Тело метода main() содержит объявление объекта
SloganAction firstObject = new SloganAction();
и вызов его метода
firstObject.printSlogan();
Вывод строки «Enabling the Information Age» в примере осуществляет метод
println() ( ln — переход к новой строке после вывода) статического поля out
класса System, который подключается к приложению автоматически вместе
с пакетом java.lang. Приведенную программу необходимо поместить в файл
FirstProgram.java (расширение. java обязательно), имя которого должно сов-
падать с именем public-класса.
Объявление классов предваряет строка
package
by.bsu.simple;
указывающая на принадлежность классов пакету с именем by.bsu.simple, кото-
рый является на самом деле каталогом на диске. Для приложения, состоящего
из двух классов, наличие пакетов не является необходимостью. Однако даже
при отсутствии слова package классы будут отнесены к пакету по умолчанию
(unnamed), размещенному в корне проекта. Если же приложение состоит из не-
скольких сотен классов, то размещение классов по пакетам является жизнен-
ной необходимостью.
Классы из примеров 2 и 3 могут сохраняться как в одном файле, так и в двух
файлах FirstProgram.java и SloganAction.java. На практике следует хранить
классы в отдельных файлах, что позволяет всем разработчикам проекта быст-
рее воспринимать концепцию приложения в целом.
ОСНОВЫ JAVA
18
/* # 4 # простое объектно-ориентированное приложение # FirstProgram.java */
package
by.bsu.simple.run;
import
by.bsu.simple.action.SloganAction; // подключение класса из пакета
public
class FirstProgram {
public
static void main(String[ ] args) {
SloganAction firstObject = new SloganAction ();
firstObject.printSlogan();
}
}
// # 5 # простой класс # SloganAction.java
package
by.bsu.simple.action;
public class
SloganAction {
public
void printSlogan() {
// вывод строки
System.out.println("Enabling the Information Age");
}
}
Простейший способ компиляции — вызов строчного компилятора из корне-
вого каталога, в котором находится каталог by, каталог bsu и так далее:
javac by/bsu/simple/action/SloganAction.java
javac by/bsu/simple/run/FirstProgram.java
При успешной компиляции создаются файлы FirstProgram.class
и SloganAction.class, имена которых совпадают с именами классов. Запустить
этот байткод можно с помощью интерпретатора Java:
java by.bsu.simple.run.FirstProgram
Здесь к имени приложения FirstProgram.class добавляется путь к пакету
от корня проекта by.bsu.simple.run, в котором он расположен.
Чтобы компилировать и выполнить приложение, необходимо загрузить
и установить последнюю версию пакета, например по адресу:
http://www.oracle.com/technetwork/java/javase/downloads/
При инсталляции рекомендуется указывать для размещения корневой ката-
лог. Если JDK установлена в директории (для Windows) c:\Java\jdk7, то ката-
лог, который компилятор Java будет рассматривать как корневой для иерархии
пакетов, можно вручную задавать с помощью переменной среды окружения
в виде: СLASSPATH=.;c:\Java\jdk7\.
Переменной задано еще одно значение «.» для использования текущей ди-
ректории, например, с:\workspace в качестве рабочей для хранения своих соб-
ственных приложений.
Чтобы можно было вызывать сам компилятор и другие исполняемые
программы, переменную PATH нужно проинициализировать в виде
PATH=c:\Java\jdk7\bin.
ВВЕДЕНИЕ В ООП И КЛАССЫ
19
Этот путь указывает на месторасположение файлов javac.exe и java.exe.
В различных версиях операционных систем путь к JDK может указываться
различными способами.
Однако при одновременном использовании нескольких различных версий
компилятора и различных библиотек применение переменных среды окружения
начинает мешать эффективной работе, так как при выполнении приложения по-
иск класса осуществляется независимо от версии. Когда виртуальная машина
обнаруживает класс с подходящим именем, она его и подгружает. Такая ситуа-
ция предрасполагает к ошибкам, порой трудноопределимым. Поэтому перемен-
ные окружения начинающим программистам лучше не определять вовсе.
Обработка аргументов командной строки, передаваемых в метод main(), отно-
сится к необходимым в самом начале обучения языку программам. Аргументы
представляют последовательность строк, разделенных пробелами, значения кото-
рых присваиваются объектам массива String[]args. Элементу args[0] присваивает-
ся значение первой строки после имен компилятора и приложения. Количество
аргументов определяется значением args.length. Поле args.length является кон-
стантным полем класса, представляющего массив, значение которого не может
быть изменено на протяжении всего жизненного цикла объекта-массива.
/* # 6 # вывод аргументов командной строки в консоль # PrintArguments.java */
package
by.bsu.arg;
public
class PrintArguments {
public
static void main(String[ ] args) {
for
(String str : args) {
System. out.printf("Aргумент-> %s%n", str);
}
}
}
В данном примере используется цикл for для неиндексируемого перебора
всех элементов и метод форматированного вывода printf(). Тот же результат
был бы получен при использовании традиционного вида цикла for
for
( int i = 0; i < args.length; i++) {
System. out.println("Aргумент-> " + args[i]);
}
Запуск этого приложения осуществляется с помощью следующей команд-
ной строки вида:
java by.bsu.arg.PrintArguments 2012 Oracle "Java SE 7"
что приведет к выводу на консоль следующей информации:
Аргумент-> 2012
Аргумент-> Oracle
Аргумент-> Java SE 7
ОСНОВЫ JAVA
20
Приложение, запускаемое с аргументами командной строки, может быть
использовано как один из примитивных способов ввода в приложение внеш-
них данных.
Основы классов и объектов Java
Классы в языке Java объединяют поля класса, методы, конструкторы, логические
блоки и внутренние классы. Основные отличия от классов C++: все функции опре-
деляются внутри классов и называются методами; невозможно создать метод,
не являющийся методом класса, или объявить метод вне класса; спецификаторы до-
ступа public, private, protected воздействуют только на те объявления полей, мето-
дов и классов, перед которыми они стоят, а не на участок от одного до другого
спецификатора, как в С++; элементы по умолчанию не устанавливаются в private,
а доступны для классов из данного пакета. Объявление класса имеет вид:
[спецификаторы] class ИмяКласса [extends СуперКласс] [implements список_интерфейсов] {
/* определение класса */
}
Спецификатор доступа к классу может быть public (класс доступен в дан-
ном пакете и вне пакета), final (класс не может иметь подклассов), abstract
(класс может содержать абстрактные методы, объект такого класса создать
нельзя). По умолчанию, если спецификатор класса не задан, он устанавливает-
ся в дружественный (friendly). Такой класс доступен только в текущем пакете.
Спецификатор friendly при объявлении вообще не используется и не является
ключевым словом языка. Это слово используется в сленге программистов, что-
бы как-то коротко обозначить значение по умолчанию.
Класс наследует все свойства и методы суперкласса, указанного после клю-
чевого слова extends, и может включать множество интерфейсов, перечислен-
ных через запятую после ключевого слова implements. Интерфейсы очень по-
хожи на абстрактные классы, содержащие только константы и сигнатуры мето-
дов без реализации.
Все классы любого приложения условно разделяются на две группы: классы —
носители информации и классы, работающие с информацией. Классы, обладаю-
щие информацией, содержат данные о предметной области приложения. Например,
если приложение предназначено для управления воздушным движением, то пред-
метной областью будут самолеты, пассажиры и пр. При проектировании классов
информационных экспертов важна инкапсуляция, обеспечивающая значениям по-
лей классов корректность информации. У рассмотренного выше класса House
есть поле numberWindows, значение которого на может быть отрицательным.
С помощью инкапсуляции ключевым словом private закрывается прямой доступ
к значению поля через объект, а метод, отвечающий за инициализацию значения
поля, будет выполнять проверку входящего значения на корректность.
ВВЕДЕНИЕ В ООП И КЛАССЫ
21
В качестве примера с нарушением инкапсуляции можно рассмотреть класс
Coin в приложении по обработке монет.
// # 7 # простой пример класса носителя информации # Coin.java
package
by.bsu.fund.bean;
public
class Coin {
public
double diameter; // нарушение инкапсуляции
private
double weight; // правильная инкапсуляция
public
double getDiameter() {
return
diameter;
}
public
void setDiameter( double value) {
if
(value > 0) {
diameter = value;
} else {
diameter = 0.01; // значение по умолчанию
}
}
public
double takeWeight() { // некорректно: неправильное имя метода
return
weight;
}
public
void setWeight( double value) {
weight = value;
}
}
Класс Coin содержит два поля diameter и weight, помеченные как public
и private. Значение поля weight можно изменять только при помощи методов,
например, setWeight ( double value). В некоторых ситуациях замена некоррект-
ного значения на значение по умолчанию может привести к более грубым
ошибкам в дальнейшем, поэтому часто вместо замены производится генерация
исключения. Поле diameter доступно непосредственно через объект класса
Coin. Поле, объявленное таким способом, считается объявленным с наруше-
нием «тугой» инкапсуляции, следствием чего может быть нарушение коррект-
ности информации, как это показано ниже:
// # 8 # демонстрация последствий нарушения инкапсуляции # Runner.java
package
by.bsu.fund.run;
import
by.bsu.fund.bean.Coin;
public
class Runner {
public
static void main(String[ ] args) {
Coin ob = new Coin();
ob.diameter = -0.12; // некорректно: прямой доступ
ob.setWeight(100);
// ob.weight = -150; // поле недоступно: compile error
}
}
ОСНОВЫ JAVA
22
Чтобы компиляция кода вида
ob.diameter = -0.12;
стала невозможной, следует поле diameter класса Coin объявить в виде
private
double diameter;
тогда строка с попыткой прямого присваивания значения поля с помощью
ссылки на объект приведет к ошибке компиляции.
// # 9 # «туго» инкапсулированный класс (Java Bean) # Coin.java
package
by.bsu.fund.bean;
public
class Coin {
private double diameter; // правильная инкапсуляция
private double weight; // правильная инкапсуляция
public double getDiameter() {
return diameter;
}
public void setDiameter( double value) {
if(value > 0) {
diameter = value;
} else {
System. out.println("Oтрицательный диаметр!");
}
}
public double getWeight() { // правильное имя метода
return weight;
}
public void setWeight( double value) {
weight = value;
}
}
Проверка корректности входящей извне информации осуществляется в ме-
тоде setDiameter(double value) и позволяет уведомить о нарушении инициали-
зации объекта. Доступ к public-методам объекта класса осуществляется только
после создания объекта данного класса.
/* # 10 # создание объекта, доступ к полям и методам объекта # CompareCoin.java
# Runner.java */
package
by.bsu.fund.action;
import
by.bsu.fund.bean.Coin;
public
class CompareCoin {
public void compareDiameter(Coin first, Coin second) {
double delta = first.getDiameter() - second.getDiameter();
if (delta > 0) {
System. out.println("Первая монета больше второй на " + delta);
} else if (delta == 0) {
ВВЕДЕНИЕ В ООП И КЛАССЫ
23
System.out.println("Монеты имеют одинаковый диаметр");
} else {
System.out.println("Вторая монета больше первой на " + -delta);
}
}
}
package
by.bsu.fund.run;
import
by.bsu.fund.bean.Coin;
import
by.bsu.fund.action.CompareCoin;
public
class Runner {
public
static void main(String[ ] args) {
Coin ob1 = new Coin();
ob1.setDiameter(-0.11); // сообщение о неправильных данных
ob1.setDiameter(0.12); // корректно
ob1.setWeight(150);
Coin ob2 = new Coin();
ob2.setDiameter(0.21);
ob2.setWeight(170);
CompareCoin ca = new CompareCoin();
ca.compareDiameter(ob1, ob2);
}
}
Компиляция и выполнение данного кода приведут к выводу на консоль сле-
дующей информации:
O
трицательный диаметр!
Вторая монета больше первой на 0.09.
Объект класса создается за два шага. Сначала объявляется ссылка на объ-
ект класса. Затем с помощью оператора new создается экземпляр объекта,
например:
Coin ob1; // объявление ссылки
ob1 = new Coin(); // создание объекта
Однако эти два действия обычно объединяют в одно:
Coin ob1 = new Coin(); /* объявление ссылки и создание объекта */
Оператор new вызывает конструктор, в данном примере конструктор
по умолчанию без параметров, но в круглых скобках могут размещаться аргу-
менты, передаваемые конструктору, если у класса объявлен конструктор с па-
раметрами. Операция присваивания для объектов означает, что две ссылки бу-
дут указывать на один и тот же участок памяти.
Метод compareDiameter(Coin first, Coin second) выполняет два действия,
которые следует разделять: выполняет сравнение и печатает отчет. Действия
слишком различны по природе, чтобы быть совмещенными. Естественным ре-
шением будет изменить возвращаемое значение метода на int и оставить в нем
только вычисления.
ОСНОВЫ JAVA
24
/* # 11 # метод сравнения экземпляров по одному полю # */
public int
compareDiameter(Coin first, Coin second) {
int
result = 0;
double
delta = first.getDiameter() - second.getDiameter();
if
(delta > 0) {
result = 1;
} else if (delta < 0) {
result = -1;
}
return
result;
}
Формирование отчета следует поместить в другой метод другого класса.
Объектные ссылки
Java работает не с объектами, а с ссылками на объекты. Это объясняет
то, что операции сравнения ссылок на объекты не имеют смысла, так как
при этом сравниваются адреса. Для сравнения объектов на эквивалентность
по значению необходимо использовать специальные методы, например,
equals(Object ob). Этот метод наследуется в каждый класс из суперкласса
Object, который лежит в корне дерева иерархии всех классов и должен перео-
пределяться в подклассе для определения эквивалентности содержимого двух
объектов этого класса.
/* # 12 # сравнение ссылок и объектов # ComparisonStrings.java */
package
by.bsu.strings;
public
class ComparisonStrings {
public
static void main(String[ ] args) {
String s1, s2;
s1 = "Java";
s2 = s1; // переменная ссылается на ту же строку
System. out.println("сравнение ссылок " + (s1 == s2)); // результат true
// создание нового объекта
s2 = new String(
" Java" ); // эквивалентно s2 = new String(s1);
System. out.println("сравнение ссылок "+ (s1 == s2)); // результат false
System. out.println("сравнение значений " + s1.equals(s2)); // результат true
}
}
В результате выполнения действия s2 = s1 получается, что обе ссылки ссы-
лаются на один и тот же объект. Оператор « ==» возвращает true при сравнении
ссылок только в том случае, если они ссылаются на один и тот же объект.
Если же ссылку инициализировать при помощи конструктора s2 = new String(s1),
то создается новый объект в другом участке памяти, который инициализируется
ВВЕДЕНИЕ В ООП И КЛАССЫ
25
значением, взятым у объекта s1. В итоге существуют две ссылки, каждая из ко-
торых независимо ссылается на объект, который никак физически не связан
другим объектом. Поэтому оператор сравнения ссылок возвращает результат
false, так как ссылки ссылаются на различные участки памяти. Объекты обла-
дают одинаковыми значениями, что легко определяется вызовом метода
equals(Object o).
Если в процессе разработки возникает необходимость в сравнении по зна-
чению объектов классов, созданных программистом, для этого следует перео-
пределить в данном классе метод equals(Object o) в соответствии с теми кри-
териями сравнения, которые существуют для объектов данного типа или
по стандартным правилам, заданным в документации.
Консоль
Консоль определяется программой, предоставляющей интерфейс команд-
ной строки для интерактивного обмена текстовыми командами и сообщениями
с операционной системой или программным обеспечением.
Взаимодействие с консолью с помощью потока (объекта класса) System.in
представляет собой один из простейших способов передачи информации
в приложение. При создании первых приложений такого рода передача в них
информации является единственно доступной для начинающего программи-
ста. В следующем примере рассматривается ввод информации в виде символа
из потока ввода, связанного с консолью, и последующего вывода на консоль
символа и его числового кода.
// # 13 # чтение символа из потока System.in # ReadCharRunner.java
package
by.bsu.console;
public
class ReadCharRunner {
public static void main(String[ ] args) {
int x;
try {
x = System.in.read();
char c = (char)x;
System.out.println("Код символа: " + c + " =" + x);
} catch (java.io.IOException e) {
System.err.println("ошибка ввода " + e);
}
}
}
Обработка исключительной ситуации IOException, которая может возник-
нуть в операциях ввода/вывода и в любых других взаимодействиях с внешни-
ми устройствами, осуществляется в методе main() с помощью реализации
ОСНОВЫ JAVA
26
блока try-catch. Если ошибок при выполнении не возникает, выполняется блок
try {}, в противном случае генерируется исключительная ситуация, и выполне-
ние программы перехватывает блок catch {}.
Ввод блока информации осуществляется посредством чтения строки из кон-
соли с помощью возможностей объекта класса Scanner, имеющего возмож-
ность соединяться практически с любым источником информации: строкой,
файлом, сокетом, адресом в Интернете, с любым объектом, из которого можно
получить ссылку на поток ввода.
// # 14 # чтение строки из консоли # RunScanner.java
package
by.bsu.console;
import
java.util.Scanner;
public
class RunScanner {
public
static void main(String[ ] args) {
System.out.println("Введите Ваше имя и нажмите :");
Scanner scan = new Scanner(System.in);
String name = scan.next();
System.out.println("Привет, " + name);
scan.close();
}
}
В результате запуска приложения будет выведено, например, следующее:
Введите Ваше имя и нажмите :
Остап
Привет, Остап.
Позже будут рассмотрены более удобные способы извлечения информации
из потока ввода с помощью класса Scanner, в качестве которого может фигури-
ровать не только консоль, но и дисковый файл, строка, сокетное соединение и пр.
Base code conventions
При выборе имени класса, поля, метода использовать цельные слова, полностью
исключить сокращения. По возможности опускать предлоги и очевидные связую-
щие слова. Аббревиатуры использовать только в том случае, когда они очевидны.
Имя класса всегдa пишется с большой буквы: Coin, Developer.
Если имя класса состоит из двух и более слов, то второе и следующие слова
пишутся слитно с предыдущим и начинаются с большой буквы: AncientCoin,
FrontendDeveloper.
Имя метода всегда пишется с маленькой буквы: perform(), execute().
Если имя метода состоит из двух и более слов, то второе и следующие слова
пишутся слитно с предыдущим и начинаются с большой буквы: performTask(),
executeBaseAction().
ВВЕДЕНИЕ В ООП И КЛАССЫ
27
Имя поля класса, локальной переменной и параметра метода всегда пишут-
ся с маленькой буквы: weight, price.
Если имя поля класса, локальной переменной и параметра метода состоит
из двух и более слов, то второе и следующие слова пишутся слитно с предыду-
щим и начинаются с большой буквы: priceTicket, typeProject.
Константы и перечисления пишутся в верхнем регистре: DISCOUNT,
MAX_RANGE.
Все имена пакетов пишутся с маленькой буквы. Сокращения допустимы
только в случае, если имя пакета слишком длинное: 10 или более символов.
Использование цифр и других символов нежелательно.
Задания к главе 1
Вариант A
1. Приветствовать любого пользова теля при вводе его имени через команд-
ную строку.
2. Отобразить в окне консоли аргументы командной строки в обратном
порядке.
3. Вывести заданное количество случайных чисел с переходом и без перехода
на новую строку.
4. Ввести пароль из командной строки и сравнить его со строкой-образцом.
5. Ввести целые числа как аргументы командной строки, подсчитать их сум-
мы (произведения) и вывести результат на консоль.
6. Вывести фамилию разработчика, дату и время получения задания, а также
дату и время сдачи задания.
Вариант B
Ввести с консоли n целых чисел. На консоль вывести:
1. Четные и нечетные числа.
2. Наибольшее и наименьшее число.
3. Числа, которые делятся на 3 или на 9.
4. Числа, которые делятся на 5 и на 7.
5. Элементы, расположенные методом пузырька по убыванию модулей.
6. Все трехзначные числа, в десятичной записи которых нет одинаковых
цифр.
7. Наибольший общий делитель и наименьшее общее кратное этих чисел.
8. Простые числа.
9. Отсортированные числа в порядке возрастания и убывания.
10. Числа в порядке убывания частоты встречаемости чисел.
11. «Счастливые» числа.
ОСНОВЫ JAVA
28
12. Числа Фибоначчи: f0 = f1 = 1, f (n) = f (n–1) + f (n–2).
13. Числа-палиндромы, значения которых в прямом и обратном порядке совпа-
дают.
14. Элементы, которые равны полусумме соседних эле ментов.
15. Период десятичной дроби p = m/n для первых двух целых положительных
чисел n и m, расположенных подряд.
16. Построить треугольник Паскаля для первого положительного числа.
Тестовые задания к главе 1
Вопрос 1.1.
Дан код программ:
A)
public class Quest21 {
public static void main (String [] args) {
System.out.println ("Hello, java 7");
}
}
B)
public class Quest22 {
String java = "Java 7";
public static void main (String [] args) {
System.out.println (java);
}
}
C)
public class Quest23 {
{
System.out.println ("Java 7");
}
}
Укажите, что скомпилируется без ошибок (выберите 1).
1) AB
2) BC
3) ABC
4) A
5) AC
Вопрос 1.2.
Выберите правильные утверждения (2):
1) класс — это тип данных;
2) объект класса может использоваться всюду, где используется объект
подкласса;
3) объект класса можно создать только один раз;
4) на объект класса может не ссылаться объектная переменная.
ВВЕДЕНИЕ В ООП И КЛАССЫ
29
Вопрос 1.3.
Вставьте на место прочерка название одного из принципов ООП так, чтобы
получилось верное определение (1):
1) наследование
2) полиморфизм
3) позднее связывание
4) инкапсуляция
__________ — это объединение данных и методов, предназначенных для
манипулирования этими данными в новом типе — классе.
Вопрос 1.4.
Дан код:
String s; // 1
if ((s = "java") == "java") {// 2
System.out.println (s+ " true");
} else {
System.out.println (s+ " false");
}
Что будет результатом компиляции и запуска этого кода (1)?
1) ошибка компиляции в строке 1, переменная не проинициализирована
2) ошибка компиляции в строке 2, неправильное выражение для оператора if
3) на консоль выведется java true
4) на консоль выведется java false
Вопрос 1.5.
Дан код:
public class Quest5 {
private static void main (String [] args) {
System.out.println (args [2]);
}
}
Что произойдет, если этот код выполняется следующей командной строкой:
java Quest5 Java 7"" (1)?
1) выведется: Java 7
2) ошибка времени выполнения NullPointerException
3) ошибка времени выполнения ArraylndexOutOfBoundsException
4) выведется: Java 7 <пустая строка>
5) выведется: <пустая строка>
6) приложение не запустится
7) код не скомпилируется
ОСНОВЫ JAVA
Вопрос 1.6.
Дан код:
public class Quest6 {
public static void main (String [] args) {
System. out.print ("A");
main ("java7");
}
private static void main (String args) {
System. out.print ("B");
}
}
Что будет выведено в результате запуска и компиляции (1)?
1) ошибка компиляции
2) BA
3) AB
4) AA
5) компиляция пройдет успешно, а при выполнении программа зациклится
Вопрос 1.7.
Дан код:
class Book {
private String book;
public void setBook (String b) {book = b;}
}
public class Quest7 {
public static void main (String [] args) {
Book book1 = new Book (); book1.setBook ("Java 7");
Book book2 = new Book (); book2.setBook ("Java 7");
if (book1.equals (book2)) {
System. out.println ("True");
} else {
System. out.println ("False");
}
}
}
Результатом компиляции и запуска кода будет (1)?
1) True
2) ошибка компиляции
3) False
4) код скомпилируется, но при выполнении оператор if будет пропущен.
|