Внимание оговорки:
В этом уроке Вы добавляете наследование в java в копилку своих знаний.
Код, примеры из которого приведены здесь, можно взять вот в этом репозитории.
Наследование — это механизм, который позволяет создавать классы на основе других классов. Это дает возможность расширять свойства наследуемого класса, и сохранять работоспособность ранее написанного кода.
Object
.Для того чтобы некий класс стал наследником другого класса, в его объявлении применяется ключевое слово extends
и имя наследуемого класса. Вот как это выглядит в коде:
class Primate extends Animal {
// ....
}
Но мы не можем написать так: class Primate extends Animal, SomeClass, Foo {
. Наследоваться можно только от одного класса.
Член класса — это либо метод, либо поле класса.
Наследование, как было сказано в видео, необходимо для того, чтобы не дублировать ранее написанный код, а использовать его же, но с новыми возможностями.
Для разнообразия приведу пример не на ветвлении класса Game
, а на упрощенной классификации животных.
Начнем с класса Animal
:
package com.critters;
public class Animal {
boolean isAlive;
int age;
// Геттеры и сеттеры упущены для экономии места в этом тексте. )
}
Не зависимо от типа, животное может быть живым или мертвым и иметь некий возраст. Пока этих полей хватит.
Далее создадим класс приматов:
package com.critters;
public class Primate extends Animal {
int numberOfLimbs;
int height;
int iq;
Sex sex;
// Геттеры и сеттеры упущены для экономии места в этом тексте. )
public enum Sex { // Модуль 5. Урок 5. Перечисления в Java.
male, female
}
}
Класс приматов будет немного сложнее. Но любой примат точно может быть живым или мертвым и иметь некий возраст. Поэтому он является наследником класса Animal
.
Далее создадим класс обезьян:
package com.critters;
public class Monkey extends Primate {
public Diet diet;
public Diet getDiet() {
return diet;
}
public void setDiet(Diet diet) {
this.diet = diet;
}
public enum Diet { // Модуль 5. Урок 5. Перечисления в Java.
omnivorous, carnivore, herbivore
}
}
Будем классифицировать обезьян по диете и на этом успокоимся. Но каждая обезьяна точно должна включать в себя все параметры примата. Поэтому класс Monkey
наследуется от класса Primate
. Получается, что в классе Monkey
мы уже не дублируем шесть полей и кучу методов к ним, а переиспользуем уже написанное!
В упомянутом выше репозитории Вы еще найдете класс HomoSapiens
как пример ветвления наследников.
Сразу же начнем с примера использования объекта класса Monkey
. Вертеть ее будем в классе CrittersUsage
.
package com;
import com.critters.Animal;
import com.critters.Monkey;
import com.critters.Primate;
public class CrittersUsage {
public static void main(String[] args) {
Object o = new Object();
Monkey monkey = new Monkey();
// Наполним обезьянку.
monkey.setDiet(Monkey.Diet.herbivore);
// Поля от предка Primate
monkey.setNumberOfLimbs(5); // иногда хвост считается конечностью
monkey.setHeightCM(110);
monkey.setIq(75);
monkey.setSex(Primate.Sex.male);
// Поля от предка Animal
monkey.setAge(15);
monkey.setAlive(true); // Оживили.
// Monkey доступны методы класса Object. В данном случае — toString()
System.out.println(monkey.toString());
printAnimalAge(monkey); // 15
printAnimalAliveStatus(monkey); // true
}
// Оба метода будут работать с любыми наследниками класса Animal
private static void printAnimalAge(Animal someAnimal) {
System.out.println(someAnimal.getAge());
}
private static void printAnimalAliveStatus(Animal someAnimal) {
System.out.println(someAnimal.isAlive());
}
}
Как видно из кода — объекту класса Monkey
доступны все члены всех классов-предков. Даже Object.toString()
. Реализован Object.toString()
слишком обобщенно, поэтому данный метод просто возвращает системное имя объекта, у которого он был вызван. В моем случае это было com.critters.Monkey@1b6d3586
.
Обратите внимание на то, что ссылки в аргументах методов printAnimalAge
& printAnimalAliveStatus
имеют тип Animal
. Это хоть и позволяет этим методам принимать на вход объекты-наследники от класса Animal
, но это же ограничивает доступность членов объекта для данных методов.
Тип ссылки ограничивает видимость членов объекта по себе. То есть, несмотря на то, что мы знаем, что в ссылках someAnimal
на самом деле представлен объект класса Monkey
, но мы сможем использовать только члены класса (типа) Animal
: isAlive(), setAlive(...), getAge(), setAge(...)
, в выше упомянутых методах.
А поля класса Animal
видны только в рамках пакета critters
, потому что они не имеют модификатора доступа.
Это означает, что видимость членов классов в наследовании работает только на верх. Наследники наследуют все свойства предков, а предкам недоступны свойства наследников.
super
— ключевое слово, позволяющее наследнику получить доступ к членам класса-предка, которые перекрыты такими же членами класса-наследника. Но наследник:
private
членам класса-предка;protected
, не зависимо от расположения в пакетах.Естественно, что public
члены любого класса светятся во весь мир.
Рассмотрим на примерах.
Для начала, добавим:
Animal
строку protected final String hiddenMember = "Animal's hidden string.";
.Primate
строки protected final String hiddenMember = "Primate's hidden first string.";
и private final String secondHiddenMember = "Primate's hidden second string.";
.Monkey
строку protected final String hiddenMember = "Monkeys's hidden string.";
. И Добавим еще сюда метод accessToHiddenMembers()
.Теперь класс Monkey
будет выглядеть так:
package com.critters;
public class Monkey extends Primate {
Diet diet;
protected final String hiddenMember = "Monkeys's hidden string.";
public Diet getDiet() {
return diet;
}
public void setDiet(Diet diet) {
this.diet = diet;
}
public enum Diet { // Модуль 5. Урок 5. Перечисления в Java.
omnivorous, carnivore, herbivore
}
public void accessToHiddenMembers() {
System.out.println(hiddenMember); // "Monkeys's hidden string."
System.out.println(super.hiddenMember); // "Primate's hidden first string."
// System.out.println(super.secondHiddenMember); // private member
// System.out.println(super.super.hiddenMember); // Так тоже нельзя.
}
}
Обратите внимание, что при помощи слова super
мы получили доступ к полю hiddenMember
класса Primate
. Хотя мы его перекрыли таким же полем в классе Monkey
.
Но мы не можем получить доступ к скрытому члену класса-предка-предка Animal
. Хотя можем пройтись по всем другим членам классов-предков вплоть до Object
. Перекрывая член класса-предка — теряем доступ к этому члену во всех классах-предках, кроме ближайшего.
Вам ответят команда поддержки Хекслета или другие студенты.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
Наши выпускники работают в компаниях:
Зарегистрируйтесь или войдите в свой аккаунт