Молодогвардейцев 454015 Россия, Челябинская область, город Челябинск 89085842764
MindHalls logo

Java — разница между extends и implements на примерах

После продолжительного программирования на C++ переходить на Java бывает болезненно. С одной стороны прославленный сборщик мусора, а с другой огромное множество принципиальных различий в подходах к программированию. Об одном таком отличии я сегодня расскажу подробнее.

Речь пойдет о наследовании в Java. В отличии от C++, где наследование могло быть множественным, здесь это не совсем так. Кроме того, привычный синтаксис через «:» заменился на целых два ключевых слова: extends и implements. Начну с первого.

Ключевое слово extends в Java

Действие ключевого слова в точности совпадает с его переводом, один класс расширяет другой, что является классическим наследованием. Правила видимости полей и методов сохранились: private доступны только в самом классе, protected в самом классе и во всех наследниках, к public методам и полям можно обращаться откуда угодно. Главное отличие от «сишного» наследования в том, что можно расширять только один класс. Я сейчас не буду рассуждать о том, насколько это удобно, скажу только, что со множественным наследованием в C++ постоянно творилась какая-то каша.

Небольшой пример наследования с помощью ключевого слова extends. Напишем класс Door, который будет описывать характеристики двери, мы можем создать объект этого класса и работать с ним, как с «просто дверью». С другой стороны напишем еще два класса: IronDoor и WoodDoor, которые будут расширять класс Door(== наследуются от класса Door), т.е. добавят свои характеристики к базовым.


//Базовый класс "дверь"
public class Door  {
    //Допустим, что у любой двери есть цена
    protected int price;

    //Этот метод тоже наследуется
    protected void doSomething() {
        System.out.println("Door is doing something");
    }

    //Этот метод доступен исключительно в классе Door
    private void onlyForDoor() {

    }
}

//Железная дверь
public class IronDoor extends Door {
    //Уровень защиты определен только для железных дверей
    private int protectionLvl;

    IronDoor(int price, int protectionLvl) {
        this.price = price;
        this.protectionLvl = protectionLvl;
    }
}

//Деревянная дверь
public class WoodDoor extends Door {
    //Характеристика "порода древесины" доступна только деревянной двери
    private String woodType;

    WoodDoor(int price, String woodType) {
        this.price = price;
        this.woodType = woodType;
    }
}

Ключевое слово implements в Java

С ключевым словом implements связано чуть больше хитростей. Слово «имплементировать» можно понимать, как «реализовывать», а в тот самый момент, когда возникает слово «реализовывать», где-то недалеко появляются интерфейсы. Так вот конструкция public class Door implements Openable означает, что класс дверь реализует интерфейс «открывающийся». Следовательно класс должен переопределить все методы интерфейса. Главная фишка в том, что можно реализовывать сколь угодно много интерфейсов.

Зачем это нужно? Самый простой пример, который приходит в голову, два интерфейса: Openable и Closeble. В первом метод open, и метод close во втором. Они помогут научить нашу дверь закрываться и открываться.

public interface Openable {
    void open();
}

public interface Closeble {
    void close();
}


public class Door implements Openable, Closeble {
    protected int price;

    protected void doSomething() {
        System.out.println("Door is doing something");
    }

    //Реализованные методы
    
    @Override
    public void open() {

    }

    @Override
    public void close() {

    }
}

В классах-потомках двери(железная и деревянная двери) тоже появятся методы открыть/закрыть, реализованные в классе Door. Но никто нам не запрещает их переопределить.

public class IronDoor extends Door {
    private int protectionLvl;

    IronDoor(int price, int protectionLvl) {
        this.price = price;
        this.protectionLvl = protectionLvl;
    }

    //Переопределяем методы
    
    @Override
    public void open() {
        System.out.println("The IRON door is opened");
    }

    @Override
    public void close() {
        System.out.println("The IRON door is closed");
    }
}

Заключение

Итак, главное отличие в том, что extends используется для наследования от класса в прямом смысле этого слова, а implements позволяет «реализовать интерфейс». На первый взгляд это кажется лишним, неудобным и непонятным, но стоит пару раз использовать по назначению и все встает на свои места. На сегодня у меня все, спасибо за внимание!