Наследование в языке программирования Java. Часть IХ

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

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

class Siemens
{
int w, h;
int Area()
{
return w*h;
}
}

Чтобы создать подкласс класса Siemens, необходимо воспользоваться ключевым словом extends:

class SiemensM55 extends Siemens
{
// члены класса
}

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

Например, в рассмотренных ранее примерах, где мы вычисляли площадь дисплея, вы можете воспользоваться методом Area() и переменными w и h. Вам не нужно переопределять переменные и метод суперкласса Siemens, но вы можете добавлять дополнительные переменные и методы для подкласса SiemensM55, реализующие свои специфические действия для этого подкласса.

Давайте рассмотрим небольшой пример по созданию суперкласса и подкласса. Как вы уже, наверное, догадались, я воспользовался маркой телефона Siemens M55 для названия подкласса. Чтобы не обижать других производителей телефонов, рассмотрим пример для телефонов компании Nokia.

// суперкласс Nokia
class Nokia
{
// высота, ширина и площадь дисплея
int dh, dw, ds;

// метод, вычисляющий площадь дисплея
int Area()
{
return dw * dh;
}
}

// подкласс NokiaE93
class Nokia310 extends Nokia
{
// высота, ширина и площадь всего телефона
int th, dw, ds;

// метод, вычисляющий площадь телефона
int tArea()
{
return tw * th;
}
}

// входная точка приложения
class RunNokia
{
public static void main (String args[])
{
// при создании объекта используется конструктор по умолчанию
NokiaE93 nokiaE93 = new NokiaE93();
// задаем значения для переменных
nokiaE93.dh = 320;
nokiaE93.dw = 240;
nokiaE93.th = 118;
nokiaE93.tw = 55;
// вычисляем площадь дисплея
ds = nokia.dArea();
// вычисляем площадь телефона
dt = nokia.tArea();
}
}

Создав подкласс NokiaE93, вы получите доступ ко всем членам суперкласса Nokia, определенные как public. Используя оператор «.» (точка), вы открываете доступ к переменным и методам суперкласса. При создании объекта суперкласса, например Nokia nokiasuper = new Nokia(), объект созданного класса может пользоваться своими членами класса, но уже члены подкласса ему не доступны.

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

Суперкласс вправе иметь сколько угодно подклассов, например, в рассмотренном примере можно создать еще десяток-другой подклассов: NokiaE95, NokiaN80, NokiaN-Gage и так далее. Но каждый из подклассов может иметь только один суперкласс. Множественные наследования в языке Java не предусмотрены. Но каждый из подклассов может иметь свой подкласс, и такая цепочка наследования может длиться до разумной бесконечности.

Конструктор суперкласса

В рассмотренном примере по созданию суперкласса и подкласса Nokia, умышленно использовался конструктор по умолчанию. Ситуация с конструкторами суперклассов требует отдельного внимания.

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

// суперкласс Nokia
class Nokia
{
// конструктор суперкласса Nokia
// тело класса Nokia
}
// подкласс NokiaSeries60
class NokiaSeries60 extends Nokia
{
// конструктор подкласса NokiaSeries60
NokiaSeries60(int a, int b);
// тело подкласса NokiaSeries60
}
// подкласс Nokia6600 для суперкласса NokiaeSeries60
class Nokia6600 extends NokiaSeries60
{
// конструктор подкласса Nokia6600
Nokia6600 (short f, short b, short c)
{
super (a, b)
// тело конструктора
}
}
// подкласс Nokia6100 для суперкласса NokiaeSeries60
class Nokia6100 extends NokiaeSeries60
{
// конструктор подкласса Nokia6100
Nokia6100 (char a, char b)
{
super (a, b)
// тело конструктора
}
// тело подкласса Nokia6100
}

Если вы желаете воспользоваться конструктором ближайшего суперкласса, в конструкторе подкласса первым должно идти ключевое слово super с параметрами для необходимого конструктора суперкласса. Ключевое слово super имеет двойную смысловую нагрузку и может использоваться не только для вызова конструктора суперкласса. Второй вариант использования ключевого слова super, заключается в доступе к невидимому члену суперкласса. Сейчас мы коснулись так называемого вопроса видимости. Вы не задумывались над тем, что будет, если методы или переменные в суперклассе и подклассе будут совпадать по именам?

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

// суперкласс Siemens
class Siemens
{
int a, b;
}
// подкласс SiemensMC62
class SiemensMC62 extends Siemens
{
int a, b;
// конструктор подкласса SiemensMC62
SiemensMC62 (int c, int d)
{
super.a = c;   // для а в суперклассе
super.b = d;   // для b в суперклассе
a = c;   // для а подкласса
b = d;   // для b подкласса
}
}

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

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

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

Содержание

Основы языка программирования Java. Часть I
Синтаксис и семантика языка Java. Часть II
Операторы языка Java. Часть III
Метод main в языках Java и Java 2 ME. Часть IV
Объекты классов в Java и Java 2 ME. Часть V
Условные и управляющие операторы Java. Часть VI
Циклы языка программирования Java. Часть VII
Массивы данных в Java и Java 2 ME. Часть VIII
Наследование в языке программирования Java. Часть IХ
Интерфейсы в Java и Java 2 ME. Часть Х
Пакеты в Java и Java 2 ME. Часть ХI