Вызов одного конструктора из другого

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

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

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

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

Пример

public abstract class D {

. . .

int g1(int s) {

. . .

}

 

public abstract void g2(String str);

 

. . .

}

 

В классе D метод g1 — это обычный метод, g2 — абстрактный, он содержит только заголовок, но не содержит реализации.

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

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

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

  • В этой ситуации всегда применяется upcasting.

Возвращаясь к примеру с печатными изданиями, можно отметить, что класс Issue можно было бы реализовать как абстрактный, определив но не реализовав в нем метод print(...). Тогда во всех порожденных классах (Book, Journal, Newspaper) пришлось бы реализовать метод print(...). Фрагмент, печатающий каталог, при этом остался бы прежним.

 

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

Все объекты в Java создаются только явно, для чего используется операция new.

Объект

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

Объекты могут исполнять определенные роли. Роль определяет отношение между классом и его экземплярами [4], выделяя определенное их подмножество. Считается, что все эти объекты похожи по своему поведению и состояниям, которые они могут принимать. Например, в системе может существовать много объектов класса Абонент, но часть из них в данный момент играет роль вызываемых, часть - вызывающих, а остальные свободны. Таким образом у этого класса мы выделили три роли.

Таким образом, в UML существует два понятия роли: роль у партнеров ассоциации и роль, которую могут исполнять объекты. В дальнейшем во избежание путаницы будем называть роль, исполняемую объектом, объектом-ролью.

Фактически, объект-роль - это некоторый промежуточный уровень абстракции между объектами и классами. Например, рассмотрим класс "человек": экземпляром этого класса является конкретный человек с именем и фамилией (его уникальным идентификатором) - Иванов Иван Петрович. У этого экземпляра могут быть состояния, например, "болен", "здоров", "спит" и т.п. В качестве объекта-роли можно привести роли: "сын", "жена", "муж". Таким образом, объект-экземпляр класса может исполнять разные роли, например роли "мужа" и "сына".

У объекта и объекта-роли есть уникальный идентификатор и строго определенные значения атрибутов.

На диаграмме объект и объект-роль представляется как прямоугольник с двумя отделениями. Верхнее отделение содержит имя объекта и имя его класса, по следующему синтаксису:

<Имя объекта>: <имя класса>

 

3)

Описание методов класса

В первом приближении методы класса (class methods) можно рассматривать как функции.

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

<тип> <имя_метода> (<аргументы>) { <тело_метода>}

Здесь <тип> — это один из базовых типов (см. таблицу выше) или пользовательский тип (т.е. некоторое имя класса). <аргументы> — это список, возможно пустой, параметров метода. <тело_метода> — собственно программный код данного метода.

Каждый аргумент или параметр метода в данном описании — это пара "<тип> <имя_аргумента>". Аргументы отделяются друг от друга запятыми.

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

Вызов методов

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

Формальное исключение составляет вызов метода класса из другого (или того же) метода данного класса, в этом случае объект можно не указывать. Но фактически объект и в данном случае имеется, это — тот объект, для которого был вызван вызывающий метод.

Рассмотрим это на примерах. Опишем класс SomeClass и в нем методы f и g.

class SomeClass { int f(int k) { . . . } void g() { . . . }}

Здесь описан метод f с одним параметром целого типа, возвращающий целое значение и метод g без параметров, не возвращающий никакого значения. Приведем примеры вызова этих методов из некоторого фрагмента программы.

a.f(x);b.g();v = b.f(3);

В приведенном фрагменте фигурируют переменные (или поля класса) a, x, b и v. Переменные a и b должны быть описаны как ссылки с типомSomeClass, переменные x и v должны быть целочисленными.

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

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

 

 

4)

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

5)

Конструкторы классов

Мы уже познакомились с понятием класса в Java. Мы определили, что класс является как бы шаблоном для создания объектов класса (экземпляров класса) и что класс состоит из полей и методов класса. Но мы еще не рассмотрели очень важную составляющую классов — конструкторы класса .

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

Разберем более подробно, что происходит при создании объекта класса.

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

Это не полная схема, а упрощенная.

Итак, что такое конструктор .

  • 1. Это специальный метод класса.
  • 2. Его имя совпадает с именем класса.
  • 3. Конструктор не возвращает никакого значения.
  • 4. Конструктор, как и любой другой метод, может иметь параметры.
  • 5. Конструктор без параметров называется конструктором по умолчанию (default constructor).
  • 6. В классе может быть несколько конструкторов. В этом случае они должны иметь разные наборы параметров.
  • 7. Если в классе нет ни одного конструктора, то генерируется пустой конструктор по умолчанию. Если в классе есть хотя бы один конструктор, то конструктор по умолчанию не генерируется.

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

SomeClass obj = new SomeClass();

В данном случае создается объект и при его создании используется конструктор без параметров (конструктор по умолчанию). Но возможен и другой вариант.

SomeClass obj = new SomeClass(1, 'a');

Здесь при создании объекта вызывается конструктор с двумя параметрами. Т.е. в классе SomeClass должен быть описан конструктор, имеющий один арифметический параметр (например, int) и один символьный параметр.

Для того чтобы обе вышеприведенные строки были корректными, описание класса SomeClass должно выглядеть примерно так.

class SomeClass { . . . public SomeClass() { // это конструктор по умолчанию . . . } SomeClass( int a, char c) { // это конструктор с двумя параметрами . . . } . . .}

Вызов одного конструктора из другого

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

public class Point { private double x, y; public Point(double x, double y) { this.x = x; this.y = y; } public Point() { this(0, 0); // вызов конструктора с двумя параметрами } . . .}

В классе Point (точка) имеется два конструктора. Один, более общий, с двумя параметрами, предназначен для конструирования точки плоскости с заданными координатами. Другой, без параметров, строит точку с координатами (0, 0). В нем для экономии кода просто вызывается первый из конструкторов с параметрами (0, 0).

Есть одно ограничение на вызов одного конструктора из другого. Такой вызов должен быть первым оператором в вызывающем конструкторе.

Работа со строками (класс String)

Первый стандартный класс Java, который мы рассмотрим — это класс String. Этот класс определен в стандартной библиотеке Java. Он используется для работы со строками.

Откроем документацию по классу String. Во-первых, обратим внимание на конструкторы класса. В документации конструкторы класса описываются сразу после описания полей класса. Конструкторы класса String предоставляют широкие возможности конструирования строк.

public String() Создает пустую строку

public String(char[] value) Создает строку из массива символов.

public String(byte[] bytes) Создает строку из массива байт, преобразуя байты в символы в соответствии с кодировкой по умолчанию.

Есть и другие конструкторы класса String.

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

String str = new String("какая-то строка");

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

String str = "какая-то строка";

Для строк определена операция сложения, которая означает конкатенацию (сцепление) строк. Определена операция сложения строки с числом. При этом сначала число преобразуется в строку, а потом выполняется конкатенация полученных строк.

Также определена операция сложения строки с любым объектом. Она выполняется так. Сначала для этого объекта вызывается метод toString(), потом выполняется конкатенация полученных строк. Метод toString() есть у всех объектов Java (рассмотрим подробнее при изучении наследования).

Примеры сложения строк с числами нам уже встречались — в операторах типа

System.out.println("результат=" + x);

Вернемся к документации по классу String. Следует обратить внимание на следующие методы этого класса.

public char charAt(int index) Выбирает из строки символ с индексом index (символы индексируются от нуля).

public int compareTo(String anotherString) Сравнивает строку с другой строкой

public int indexOf(int ch) Ищет символ в строке

public int indexOf(String str) Ищет указанную параметром строку в данной

public int length() Возвращает длину строки

public String substring(int beginIndex, int endIndex) Выделяет подстроку из строки

public String trim() Удаляет из строки начальные и концевые пробелы

Набор методов valueOf(...) позволяет переводить значения различных типов в строки.

 

 

6)

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

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

 

8)

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

Отметим, что пакет физически содержит сущности, определенные в нем (говорят, что "сущности принадлежат пакету"). Это означает, что если будет уничтожен пакет, то будут уничтожено и все его содержимое.

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

Обычно физически библиотека — это jar-файл (rt.jar, например). Но свою личную библиотеку можно сделать и просто в каком-либо каталоге. Кроме того, библиотека может быть zip-файлом.

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

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

java.appletjava.awtjava.awt.colorjava.awt.datatransferjava.awt.dndjava.awt.eventjava.awt.fontjava.awt.geomjava.awt.imjava.awt.im.spijava.awt.imagejava.awt.image.renderablejava.awt.printjava.beansjava.beans.beancontextjava.iojava.langjava.lang.refjava.lang.reflectjava.mathjava.netjava.rmijava.rmi.activationjava.rmi.dgcjava.rmi.registryjava.rmi.serverjava.securityjava.security.acljava.security.certjava.security.interfacesjava.security.specjava.sqljava.textjava.utiljava.util.jarjava.util.zipjavax.accessibilityjavax.namingjavax.naming.directoryjavax.naming.eventjavax.naming.ldapjavax.naming.spijavax.rmijavax.rmi.CORBAjavax.sound.midijavax.sound.midi.spijavax.sound.sampledjavax.sound.sampled.spijavax.swingjavax.swing.borderjavax.swing.colorchooserjavax.swing.eventjavax.swing.filechooserjavax.swing.plafjavax.swing.plaf.basicjavax.swing.plaf.metaljavax.swing.plaf.multijavax.swing.tablejavax.swing.textjavax.swing.text.htmljavax.swing.text.html.parserjavax.swing.text.rtfjavax.swing.treejavax.swing.undojavax.transactionorg.omg.CORBAorg.omg.CORBA_2_3org.omg.CORBA_2_3.portableorg.omg.CORBA.DynAnyPackageorg.omg.CORBA.ORBPackageorg.omg.CORBA.portableorg.omg.CORBA.TypeCodePackageorg.omg.CosNamingorg.omg.CosNaming.NamingContextPackageorg.omg.SendingContextorg.omg.stub.java.rmi

Нужно разобраться с именами пакетов. Как видно, имя составное, разделенное точками. Это связано с общепринятым в Java принципом построения имен пакетов. Этот принцип состоит в том, что в имени пакета присутствует Internet-адрес разработчика пакета в обратном порядке. На примере:

Пусть Ваш адрес petr@provider.da . Тогда все имена пакетов Ваших приложений должны начинаться с "da.provider.petr.". Так, для пакета, содержащего вспомогательные сервисные классы подойдет имя "da.provider.petr.util".

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