Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Модуль 3. Урок 4. Наследование в Java. Введение в Java

alt text Внимание оговорки:

  • 16:51 Доступен метод предка, а не потомка.
  • 22:30 вместо слова "метод" подразумевается слово "класс".

В этом уроке Вы добавляете наследование в java в копилку своих знаний.

Код, примеры из которого приведены здесь, можно взять вот в этом репозитории.

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

  • Все классы в мире 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. Перекрывая член класса-предка — теряем доступ к этому члену во всех классах-предках, кроме ближайшего.


Дополнительная практика по теме.


Полезные ссылки


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

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

  • 120 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»