Два интерфейса с одинаковой сигнатурой метода, реализованные в классе Java - PullRequest
16 голосов
/ 26 марта 2012

У меня есть два интерфейса Java и один реализующий класс.

(Я использовал Eclipse для непосредственного запуска программы, и я не пытался проверить какие-либо предупреждения компилятора и т. Д. Путем явной компиляции из командной строки.)

Почему они работают без проблем? Почему Java допускает это, даже если она удовлетворяет «контракту» обоих интерфейсов, но создает неоднозначность в реализации класса?

Обновлен пример.

public interface CassettePlayer {
    void play();
}

public interface DVDPlayer {
    void play();
}

public class CarPlayer implements CassettePlayer,DVDPlayer{

    @Override
    public void play() {
        System.out.println("This plays DVD, screw you Cassette !");
    }

    public static void main(String args[]) {
        CarPlayer cp = new CarPlayer();
        cp.play();

        CassettePlayer firstInterface = new CarPlayer();
        firstInterface.play();

        DVDPlayer secondInterface = new CarPlayer();
        secondInterface.play();
    }
}

Ответы [ 7 ]

38 голосов
/ 26 марта 2012

Этот сценарий специально разрешен в Спецификации языка Java, раздел 8.1.5 :

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

interface Fish { int getNumberOfScales(); }
interface Piano { int getNumberOfScales(); }
class Tuna implements Fish, Piano {
   // You can tune a piano, but can you tuna fish?
   int getNumberOfScales() { return 91; }
}

метод getNumberOfScales в классе Tuna имеет имя, сигнатуру и тип возвращаемого значения, которые соответствуют методу, объявленному в интерфейсе Fish, а также методуобъявлено в интерфейсе Piano;считается, что он реализует и то, и другое.

Далее в тексте отмечается, что если бы сигнатуры методов имели разные типы возврата, такие как double и int, не было бы никакого способа реализоватьоба интерфейса в одном и том же классе и ошибка времени компиляции.

5 голосов
/ 07 декабря 2012

Для решения этой проблемы необходимо понять, для чего предназначены интерфейсы.

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

Итак, если вам нужен класс, реализующий «DVDPlayer» (потому что вам нужен метод «play ()»), вы найдете CarPlayer.То же самое касается необходимости класса, реализующего CassettePlayer.Это техническое объяснение.

Но, конечно, в своем семантическом кодировании вы должны убедиться, что метод carPlayer "play ()" удовлетворяет семантике как DVDPlayer, так и CassettePlayer.Я думаю, что в практическом приложении это будет плохая практика.

Конечно, в вашем примере плохая идея иметь два интерфейса, объявляющих один и тот же метод.С практической точки зрения вы должны были создать интерфейс «Player» с методом «play ()» и иметь два других, более специфических интерфейса DVDPlayer и CassettePlayer (со специальными методами для DVD и кассет), которые наследуются от Player.С другой стороны, если вам не нужны специальные методы для DVD или кассет, тогда вам не нужны два разных интерфейса, реализующих только один и тот же метод - просто используйте один интерфейс Player, этого будет достаточно.

2 голосов
/ 13 апреля 2015

В этой ситуации проблем нет, поскольку оба интерфейса имеют одинаковую сигнатуру метода. Но как насчет этого?

interface Animal {
    public void eat() throws IOException;
}

interface Plants {
    public void eat() throws NullPointerException;
}

Какой из них выбран компилятором? Почему он получает ошибку ниже кода?

public class Test implements Animal, Plants {

    public void eat() throws IOException {

    }
}

Компилятор говорит: Исключение IOException не совместимо с предложением throws в Plants.eat ()

1 голос
/ 24 ноября 2013

На следующей странице приведен пример класса который реализует два интерфейса, которые имеют

1) то же имя переменной 2) одинаковый метод в каждом интерфейсе.

http://www.j2eeonline.com/java-tm-fundamentals-II/module2/interface-ambiguous-fields.jsp

1 голос
/ 26 марта 2012

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

1 голос
/ 26 марта 2012

Почему бы и нет? Класс удовлетворяет контрактам, определенным обоими интерфейсами.

1 голос
/ 26 марта 2012

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

...