Перейти к содержанию

Implements и Extends в Java

В этом руководстве обсудим наследование, одну из важнейших концепций объектно-ориентированного программирования. В Java два основных ключевых слова, используемых для наследования, — это extends и implements.

Extends или implements

Обсудим различия между обоими ключевыми словами.

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

С другой стороны, мы используем ключевое слово implements для реализации интерфейса. Интерфейс состоит только из абстрактных методов. Класс будет реализовывать интерфейс и определять эти абстрактные методы в соответствии с требуемой функциональностью. В отличие от extends, любой класс может реализовывать несколько интерфейсов.

Хотя оба ключевых слова согласуются с концепцией наследования, ключевое слово implements в первую очередь связано с абстракцией и используется для определения контракта, а extends используется для расширения существующей функциональности класса.

Реализация

Перейдем к реализации и подробно рассмотрим extends, implements и множественное наследование.

Extends

Начнем с создания класса Media с id, name и artist. Этот класс будет действовать как базовый класс. VideoMedia и AudioMedia расширят функциональность этого класса:

public class Media {

    private int id;
    private String title;
    private String artist;
    // стандартные геттеры и сеттеры
}

Теперь создадим еще один класс с именем VideoMedia, который расширяет класс Media, наследуя его свойства. Кроме того, он имеет собственные свойства, такие как resolution и aspectRatio:

public class VideoMedia extends Media {

    private String resolution;
    private String aspectRatio;
    // стандартные геттеры и сеттеры
}

Точно так же класс AudioMedia расширяет класс Media и будет иметь собственные дополнительные свойства, такие как bitrate и frequency:

public class AudioMedia extends Media {

    private int bitrate;
    private String frequency;
    // стандартные геттеры и сеттеры

    @Override
    public void printTitle() {
        System.out.println("AudioMedia Title");
    }
}

Создадим объекты для базового и производного классов, чтобы посмотреть на унаследованные свойства:

Media media = new Media();
media.setId(001);
media.setTitle("Media1");
media.setArtist("Artist001");

AudioMedia audioMedia = new AudioMedia();
audioMedia.setId(101);
audioMedia.setTitle("Audio1");
audioMedia.setArtist("Artist101");
audioMedia.setBitrate(3500);
audioMedia.setFrequency("256kbps");

VideoMedia videoMedia = new VideoMedia();
videoMedia.setId(201);
videoMedia.setTitle("Video1");
videoMedia.setArtist("Artist201");
videoMedia.setResolution("1024x768");
videoMedia.setAspectRatio("16:9");

System.out.println(media);
System.out.println(audioMedia);
System.out.println(videoMedia);

Все три класса выводят связанные свойства:

Media{id=1, title='Media1', artist='Artist001'}
AudioMedia{id=101, title='Audio1', artist='Artist101', bitrate=3500, frequency='256kbps'} 
VideoMedia{id=201, title='Video1', artist='Artist201'resolution='1024x768', aspectRatio='16:9'}

Implements

Чтобы понять абстракцию и интерфейсы, создадим интерфейс MediaPlayer с двумя методами, называемыми play и pause. Как упоминалось ранее, все методы в этом интерфейсе являются абстрактными. Другими словами, интерфейс содержит только объявления методов.

В Java интерфейсы не должны явно объявлять метод как abstract или public. Классы, реализующие интерфейс MediaPlayer, будут определять следующие методы:

public interface MediaPlayer {

    void play();

    void pause();
}

Класс AudioMediaPlayer реализует MediaPlayer и определяет методы play и pause для аудиофайлов:

public class AudioMediaPlayer implements MediaPlayer {

    @Override
    public void play() {
        System.out.println("AudioMediaPlayer is Playing");
    }

    @Override
    public void pause() {
        System.out.println("AudioMediaPlayer is Paused");
    }
}

Точно так же VideoMediaPlayer реализует MediaPlayer и предоставляет определение метода для воспроизведения и приостановки видео:

public class VideoMediaPlayer implements MediaPlayer {

    @Override
    public void play() {
        System.out.println("VideoMediaPlayer is Playing");
    }

    @Override
    public void pause() {
        System.out.println("VideoMediaPlayer is Paused");
    }
}

Далее создадим экземпляры AudioMediaPlayer и VideoMediaPlayer и вызовем методы play и pause для них обоих:

AudioMediaPlayer audioMediaPlayer = new AudioMediaPlayer();
audioMediaPlayer.play();
audioMediaPlayer.pause();

VideoMediaPlayer videoMediaPlayer = new VideoMediaPlayer();
videoMediaPlayer.play();
videoMediaPlayer.pause();

AudioMediaPlayer и VideoMediaPlayer вызывают соответствующие реализации play и pause:

AudioMediaPlayer is Playing
AudioMediaPlayer is Paused

VideoMediaPlayer is Playing
VideoMediaPlayer is Paused

Множественное наследование

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

Создадим интерфейс AdvancedPlayerOptions:

public interface AdvancedPlayerOptions {

    void seek();

    void fastForward();
}

Класс MultiMediaPlayer реализует MediaPlayer и AdvancedPlayerOptions и определяет методы, объявленные в обоих интерфейсах:

public class MultiMediaPlayer implements MediaPlayer, AdvancedPlayerOptions {

    @Override
    public void play() {
        System.out.println("MultiMediaPlayer is Playing");
    }

    @Override
    public void pause() {
        System.out.println("MultiMediaPlayer is Paused");
    }

    @Override
    public void seek() {
        System.out.println("MultiMediaPlayer is being seeked");
    }

    @Override
    public void fastForward() {
        System.out.println("MultiMediaPlayer is being fast forwarded");
    }
}

Теперь создадим экземпляр класса MultiMediaPlayer и вызовем все реализованные методы:

MultiMediaPlayer multiMediaPlayer = new MultiMediaPlayer();
multiMediaPlayer.play();
multiMediaPlayer.pause();
multiMediaPlayer.seek();
multiMediaPlayer.fastForward();

Как и ожидалось, MultiMediaPlayer вызывает свои реализации play и pause:

MultiMediaPlayer is Playing
MultiMediaPlayer is Paused 
MultiMediaPlayer is being seeked 
MultiMediaPlayer is being fast forwarded

Заключение

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

Код статьи доступен на GitHub.

Оригинал