
- •Конструкторы классов
- •Наследование
- •Модификаторы видимости
- •Перегрузка
- •Полиморфизм
- •Приемы программирования: наследование и полиморфизм
- •Конструктор по умолчанию
- •Вызов конструктора суперкласса
- •Приведение типов
- •Оператор instanceof
- •Анонимные и вложенные классы
- •Модификатор static
- •Модификатор final
- •Абстрактные классы
- •Множественное наследование
- •Описание интерфейса
- •Реализация интерфейса
- •Переменные интерфейсного типа
- •Приемы программирования: пример применения интерфейсов
- •Пакеты и области видимости Пакеты
- •Импортирование пакетов
- •Файловая структура Java-проекта
- •Области видимости классов
- •Области видимости членов класса
- •Области видимости переменных
- •Конфликты имен
- •Ход работы:
- •Задание №1
- •Задание №2
- •Задание №2
- •Задание № 3
- •Контрольные вопросы:
Модификатор static
Любой член класса можно объявить статическим, указав перед его объявлением ключевое слово static. Статический член класса «разделяется» между всеми его объектами.
Для поля это означает, что любое изменение его значения, сделанное одним из объектов класса, сразу же «увидят» все остальные объекты.
Метод, объявленный с модификатором static, «дает обещание» не изменять никаких полей класса, кроме статических.
Для обращения к статическому члену класса можно использовать любой объект этого класса. Более того, это обращение можно осуществлять даже тогда, когда не создано ни одного такого объекта. Вместо имени объекта можно просто указывать имя класса.
Модификатор final
Любое поле класса можно объявить неизменяемым, указав перед его объявлением ключевое слово final. Неизменяемому полю можно присвоить значение только один раз (обычно это делается сразу при объявлении).
Константы в языке Java очевидным образом описываются путем совмещения модификаторов static и final. Например, мы можем объявить константу PI (лучше это делать в основном классе, а не в классе Dog), написав:
final static double PI = 3.14;
Если ключевое слово final указать перед объявлением метода, это будет обозначать, что метод нельзя переопределять при наследовании (т. е. данная версия метода будет окончательной).
Перед объявлением класса модификатор final ставится в том случае, если необходимо запретить от него наследование.
Абстрактные классы
При построении иерархии наследования часто оказывается, что метод, общий для всех подклассов и поэтому определенный в суперклассе, не может быть запрограммирован в этом суперклассе никаким полезным алгоритмом, поскольку в каждом подклассе он разный.
Например, классы Point (точка), Circle (круг) и Rectangle (прямоугольник) унаследованы от класса Figure (фигура). В классе Figure есть метод paint(), общий для всех подклассов – он нужен, чтобы нарисовать фигуру. Но между рисованием круга, точки и прямоугольника нет ничего общего, поэтому бессмысленно программировать этот метод в классе Figure.
В таких случаях после заголовка метода и списка параметров вместо фигурных скобок ставится точка с запятой, а перед объявлением метода указывается ключевое слово abstract. Такой метод называется абстрактным, т. е. лишенным реализации.
Класс, в котором есть хотя бы один абстрактный метод, называется абстрактным классом и перед словом class должно также стоять слово abstract.
Создать объект абстрактного класса нельзя. Можно только унаследовать от этого класса другие классы, переопределить в них абстрактные методы (наполнив их конкретным содержимым) и создавать объекты уже этих классов.
Множественное наследование
Множественным наследованием называется ситуация, когда класс наследует от двух или более классов.
Пусть, например, уже разработаны классы Clock (часы) и Phone (телефон) и возникает необходимость написать новый класс Cellurar (сотовый телефон), который совмещает в себе структуру и поведение обоих этих классов (его можно использовать как телефон, но он обладает также всей функциональностью часов). Очень удобно просто унаследовать класс Cellular от классов Clock и Phone. Во-первых, программисту не приходится заново переписывать многочисленные методы. Во-вторых, сохраняются все преимущества полиморфизма: объект класса Cellular можно использовать в программе и в качестве часов (как объект класса Clock) и в качестве телефона (как объект класса Phone).
Однако множественное наследование потенциально способно породить трудноразрешимые проблемы. Они начинаются, когда у классов-предков есть методы с одинаковыми сигнатурами (т.е. именем и числом параметров).
Например, в классе Clock есть метод ring(), который вызывается, когда срабатывает таймер будильника. Но в классе Phone тоже есть метод ring(), который вызывается, когда кто-то звонит по телефону и надо оповестить об этом владельца. Когда класс Cellular наследует от классов Clock и Phone, он получает метод ring(), но неизвестно какой из его вариантов.
У этой ситуации нет безупречного решения. Поэтому многие языки программирования запрещают множественное наследование.
Java множественное наследование не поддерживает.
Заметим, однако, что если метод ring() хотя бы в одном из классов Clock и Phone является абстрактным, то конфликта возникнуть не может. Абстрактный метод не имеет реализации, а следовательно «побеждает» тот метод, который абстрактным не является. Если же метод является абстрактным в обоих классах, он останется таким же и в их потомке.
Используя эту особенность абстрактных классов, авторы языка Java ввели в него особенную конструкцию – интерфейсы, позволяющие сохранить часть преимуществ множественного наследования (а именно преимущества полиморфизма), избежав при этом главной проблемы множественного наследования.