ООП в примерах. Часть 2. Наследование
от aNNiMON
Продолжаем осваивать ООП.
Разберёмся с наследованием.
Наследование позволяет взять доступные свойства родительского (базового) класса и использовать их в производных (потомках).
Сразу пример.
Вернём наш класс пункта меню в первоначальный вид:Теперь давайте создадим производный класс с цветом пункта меню:
Первое, что бросается в глаза это ключевое слово extends. Оно означает, что новый класс будет унаследован от класса MenuItem, то есть будет брать все его свойства.
Второе нововведение это super(name). super означает обращение к родительскому классу (то есть классу MenuItem). В данном случае мы обращаемся к конструктору родительского класса: public MenuItem(String name).
При вызове конструктора public ColorMenuItem(String name, int color) строка name передастся конструктору public MenuItem(String name), затем (уже внутри класса MenuItem) произойдёт присваивание переменной члену класса: this.name = name; После этого выполнение конструктора базового класса выполнится и начнут выполняться следующие операторы уже в нашем классе ColorMenuItem: this.color = color;
Ещё раз, что будет выполнено:
super(name) класса ColorMenuItem
----this.name = name; класса MenuItem
this.color = color; класса ColorMenuItem
Теперь давайте сделаем ещё один производный класс, на этот раз с иконкой:
Теперь вызов будет таков:
super(name) класса IconMenuItem
----this.name = name; класса MenuItem
createIcon(iconName) класса IconMenuItem
--icon = Image.createImage("/" + iconName); класса IconMenuItem
--//если такой картинки нет, то будет вызван icon = Image.createImage(18, 18);
Ещё раз напомню, во всех этих трёх классах метод getName() будет доступен, так как он не объявлен как private, а значит распространяется на все производные классы.
Перепишем сам класс меню OopMenu3.java
Обратите внимание, мы можем в массив MenuItem класть элементы производных классов.
Так тоже можно: MenuItem item = new ColorMenuItem("Name", 0x00);
Но мы не сможем получить доступ к методу getColor, надо конкретно указывать тип: ((ColorMenuItem) item).getColor();
А вот так написать мы можем, но работать не будет: ((IconMenuItem) item).getIcon()
Это потому что у нас инициализируется объект ColorMenuItem и мы не можем привести его к другому наследуемому типу.
Получить доступ к методу getName() мы можем из любого класса:
Это всё будет работать.
Разберём теперь это:
instanceof проверяет, объект какого класса лежит перед нами. Ведь мы положили разные объекты в один массив, поэтому чтобы правильно вызвать метод getColor или getIcon, нужно знать, что перед нами именно ColorMenuItem и IconMenuItem соответственно. Если пункт меню - объект класса IconMenuItem (item instanceof IconMenuItem), то мы можем безболезненно привести item к типу IconMenuItem и достучаться к методу getIcon, чтобы нарисовать картинку.
Вообще, использование instanceof очень тормозит выполнение программы, поэтому не следует им злоупотреблять, особенно в цикле или при отрисовке.
В следующей статье я покажу, как с помощью переопределения методов можно сделать красивый компактный быстрый код.
OOP-Demo.zip
Следующая статья →Разберёмся с наследованием.
Наследование позволяет взять доступные свойства родительского (базового) класса и использовать их в производных (потомках).
Сразу пример.
Вернём наш класс пункта меню в первоначальный вид:
- public class MenuItem {
- private String name;
- public MenuItem(String name) {
- this.name = name;
- }
- public String getName() {
- return name;
- }
- }
- public class ColorMenuItem extends MenuItem {
- private int color;
- public ColorMenuItem(String name, int color) {
- super(name);
- this.color = color;
- }
- public int getColor() {
- return color;
- }
- }
Второе нововведение это super(name). super означает обращение к родительскому классу (то есть классу MenuItem). В данном случае мы обращаемся к конструктору родительского класса: public MenuItem(String name).
При вызове конструктора public ColorMenuItem(String name, int color) строка name передастся конструктору public MenuItem(String name), затем (уже внутри класса MenuItem) произойдёт присваивание переменной члену класса: this.name = name; После этого выполнение конструктора базового класса выполнится и начнут выполняться следующие операторы уже в нашем классе ColorMenuItem: this.color = color;
Ещё раз, что будет выполнено:
super(name) класса ColorMenuItem
----this.name = name; класса MenuItem
this.color = color; класса ColorMenuItem
Теперь давайте сделаем ещё один производный класс, на этот раз с иконкой:
- public class IconMenuItem extends MenuItem {
- private Image icon;
- public IconMenuItem(String name, String iconName) {
- super(name);
- createIcon(iconName);
- }
- public Image getIcon() {
- return icon;
- }
- private void createIcon(String iconName) {
- try {
- icon = Image.createImage("/" + iconName);
- } catch (IOException ex) {
- icon = Image.createImage(18, 18);
- }
- }
- }
super(name) класса IconMenuItem
----this.name = name; класса MenuItem
createIcon(iconName) класса IconMenuItem
--icon = Image.createImage("/" + iconName); класса IconMenuItem
--//если такой картинки нет, то будет вызван icon = Image.createImage(18, 18);
Ещё раз напомню, во всех этих трёх классах метод getName() будет доступен, так как он не объявлен как private, а значит распространяется на все производные классы.
Открыть спойлер
А вот наоборот нельзя. Класс MenuItem ничего не знает про своих потомков. Он не может получить доступ к полю color, icon и методам getIcon(), getColor().Перепишем сам класс меню OopMenu3.java
Обратите внимание, мы можем в массив MenuItem класть элементы производных классов.
Так тоже можно: MenuItem item = new ColorMenuItem("Name", 0x00);
Но мы не сможем получить доступ к методу getColor, надо конкретно указывать тип: ((ColorMenuItem) item).getColor();
А вот так написать мы можем, но работать не будет: ((IconMenuItem) item).getIcon()
Это потому что у нас инициализируется объект ColorMenuItem и мы не можем привести его к другому наследуемому типу.
Получить доступ к методу getName() мы можем из любого класса:
- ColorMenuItem cmItem = new ColorMenuItem("Name", 0x00);
- cmItem.getName();
- IconMenuItem imItem = new IconMenuItem("Name", "icon.png");
- imItem.getName();
Разберём теперь это:
- MenuItem item = items[i];
- if (item instanceof IconMenuItem) {
- g.drawImage(((IconMenuItem) item).getIcon(), width / 4, startY + itemHeight * i, Graphics.TOP | Graphics.RIGHT);
- } else if (item instanceof ColorMenuItem) {
- g.setColor(((ColorMenuItem)item).getColor());
- } else {
- // item - MenuItem
- g.setColor(0xFF095E15);
- }
Вообще, использование instanceof очень тормозит выполнение программы, поэтому не следует им злоупотреблять, особенно в цикле или при отрисовке.
В следующей статье я покажу, как с помощью переопределения методов можно сделать красивый компактный быстрый код.
OOP-Demo.zip
Часть 3. Переопределение методов, уровни абстракции