Как Java-интерфейсы моделируют множественное наследование?

Я читаю "Учебник по Java" (второй раз). Я только что прошел через раздел "Интерфейсы" (снова), но до сих пор не понимаю, как Java-интерфейсы имитируют множественное наследование. Есть ли более четкое объяснение, чем то, что в книге?

Ответы

Ответ 1

Предположим, у вас есть 2 вида вещей в вашем домене: Грузовые автомобили и Кухни

У грузовиков есть метод driveTo() и Kitchens метод cook().

Теперь предположим, что Паули решает продать пиццу со спины грузовика. Он хочет, чтобы он мог ездить() и варить() с помощью.

В С++ он использовал бы множественное наследование для этого.

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

Итак, в Java мы стараемся реализовать множественное наследование с помощью делегаций:

Паули подклассифицирует грузовик и добавляет кухню к грузовику в переменной-члене, называемой кухней. Он реализует интерфейс кухни, вызывая kitchen.cook().

class PizzaTruck extends Truck implements Kitchen {
   Kitchen kitchen;

   public void cook(Food foodItem) {
      kitchen.cook(foodItem);
   }
}

Он счастливый человек, потому что теперь он может делать такие вещи, как:

pizzaTruck.driveTo(beach);
pizzaTruck.cook(pizzaWithExtraAnchovies);

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

(обновление: с появлением интерфейсов методов по умолчанию теперь также можно обеспечить некоторое наследование)

Ответ 2

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

Интерфейсы допускают множественное наследование типов, например. a class Waterfowl extends Bird implements Swimmer может использоваться другими классами, как если бы он был Bird и как если бы он был Swimmer. Это более глубокий смысл множественного наследования: позволяет одному объекту действовать так, как будто он принадлежит нескольким несвязанным различным классам одновременно.

Ответ 3

Вот способ достижения множественного наследования через интерфейсы в java.

Что нужно сделать?
класс A расширяет B, C//это невозможно в java напрямую, но может быть достигнуто косвенно.

class B{
   public void getValueB(){}
}

class C{
   public void getValueC(){}
}


interface cInterface{
   public getValueC();
}

class cChild extends C implemets cInterface{
    public getValueC(){

      // implementation goes here, call the super class getValueC();

    }
}


// Below code is **like** class A extends B, C 
class A extends B implements cInterface{
   cInterface child =  new cChild();
   child.getValueC();
}

Ответ 4

учитывая два интерфейса ниже...

interface I1 {
  abstract void test(int i);
}
interface I2 {
  abstract void test(String s);
}

Мы можем реализовать оба эти кода с помощью кода ниже...

public class MultInterfaces implements I1, I2 {
  public void test(int i) {
    System.out.println("In MultInterfaces.I1.test");
  }
  public void test(String s) {
    System.out.println("In MultInterfaces.I2.test");
  }
  public static void main(String[] a) {
    MultInterfaces t = new MultInterfaces();
    t.test(42);
    t.test("Hello");
  }
}

Мы не можем расширять два объекта, но мы можем реализовать два интерфейса.

Ответ 5

Интерфейсы не моделируют множественное наследование. Создатели Java считали, что множественное наследование неверно, поэтому на Java нет такой вещи.

Если вы хотите объединить функциональность двух классов в единую композицию объекта. То есть.

public class Main {
    private Component1 component1 = new Component1();    
    private Component2 component2 = new Component2();
}

И если вы хотите выставить определенные методы, определите их и позвольте им делегировать вызов соответствующему контроллеру.

Здесь интерфейсы могут пригодиться - если Component1 реализует интерфейс Interface1 и Component2 реализует Interface2, вы можете определить

class Main implements Interface1, Interface2

Таким образом, вы можете использовать объекты взаимозаменяемо, где это позволяет контекст.

Ответ 6

Вы знаете, что, исходя из перспективы JavaScript-разработчика, пытающегося понять, что происходит с этим материалом, я хотел бы указать пару вещей, и кто-нибудь, пожалуйста, сообщите мне, что мне здесь не хватает, если Я не в курсе.

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

Итак, зачем вам их использовать? Большую часть времени вы этого не сделали. Вы, конечно, не хотели бы использовать их ВСЕ, как многие думают. Но прежде чем я доберусь, когда вы это сделаете, расскажите о том, что они НЕ.

Интерфейсы НЕ:

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

Они действительно такие же простые, как вы думаете, они на первый взгляд. Люди злоупотребляют глупо все время, поэтому трудно понять, в чем дело. Это просто проверка/тестирование. После того, как вы написали что-то, соответствующее интерфейсу и работает, удаление этого кода "реализует" ничего не сломает.

Но если вы правильно используете интерфейсы, вы не захотите его удалить, потому что, имея его, он дает следующему разработчику инструмент для записи уровня доступа для другого набора баз данных или веб-сервисов, в котором они хотят, чтобы остальная часть вашего приложение, чтобы продолжать использовать, потому что они знают, что их класс потерпит неудачу, пока они не получат 100% -ный полный-ожидаемый интерфейс. Все интерфейсы действительно подтверждают ваш класс и устанавливают, что вы фактически реализовали интерфейс, как вы и обещали. Ничего больше.

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

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

Ответ 7

Это довольно просто. Вы можете реализовать более одного интерфейса в типе. Например, у вас может быть реализация List, которая также является экземпляром Deque (а Java делает... LinkedList).

Вы просто не можете наследовать реализации от нескольких родителей (т.е. расширить несколько классов). Объявления (сигнатуры методов) не являются проблемой.

Ответ 8

Это не симуляция множественного наследования. В java вы не можете наследовать от двух классов, но если вы реализуете два интерфейса "кажется, что вы унаследованы от двух разных классов", потому что вы можете использовать свой класс как любую из ваших двух целей.

Например

interface MyFirstInteface{
    void method1();
}
interface MySecondInteface{
    void method2();
}
class MyClass implements MyFirstInteface, MySecondInteface{
    public void method1(){
        //Method 1
    }
    public void method2(){
        //Method 2
    }

    public static void main(String... args){
        MyFirstInterface mfi = new MyClass();
        MySecondInterface msi = new MyClass();
    }
}

Это будет работать, и вы можете использовать mfi и msi, это похоже на множественное наследование, но это не потому, что вы ничего не наследуете, вы просто переписываете общедоступные методы, предоставляемые интерфейсами.

Ответ 9

Вы должны быть точными:

Java допускает множественное наследование интерфейса, но только одно наследование реализации.

Вы выполняете множественное наследование интерфейса в Java следующим образом:

public interface Foo
{
    String getX(); 
}

public interface Bar
{
    String getY();
}

public class MultipleInterfaces implements Foo, Bar
{
    private Foo foo;
    private Bar bar;

    public MultipleInterfaces(Foo foo, Bar bar)
    {
        this.foo = foo;
        this.bar = bar;
    }

    public String getX() { return this.foo.getX(); }
    public String getY() { return this.bar.getY(); }
}

Ответ 10

Кстати, причина, по которой Java не реализует полное множественное наследование, состоит в том, что она создает неоднозначность. Предположим, вы могли бы сказать: "A расширяет B, C", а затем B и C имеют функцию "void f (int)". Какая реализация наследует? С помощью подхода Java вы можете реализовать любое количество интерфейсов, но интерфейсы объявляют только подпись. Поэтому, если два интерфейса включают функции с одной и той же сигнатурой, отлично, ваш класс должен реализовать функцию с этой сигнатурой. Если интерфейсы, которые вы наследуете, имеют функции с разными сигнатурами, то функции не имеют ничего общего друг с другом, поэтому не возникает конфликта.

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

Ответ 11

Нечестно сказать, что интерфейсы "имитируют" множественное наследование.

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

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

ИЛИ Возможное решение для достижения чего-то множественного наследования похоже на интерфейс Mixin - http://csis.pace.edu/~bergin/patterns/multipleinheritance.html. Используйте с осторожностью!

Ответ 12

Они не делают.

Я думаю, что путаница исходит от людей, полагающих, что реализация интерфейса представляет собой некоторую форму наследования. Это не так; реализация может просто быть пустым, никакое поведение не принуждается действием или не гарантируется каким-либо контрактом. Типичным примером является Clonable-интерфейс, который придает большое значение большой функциональности, которая так мало определяет, что она практически бесполезна и потенциально опасна.

Что вы наследуете, реализуя интерфейс? Bubkes! Поэтому, на мой взгляд, прекратите использовать интерфейс слов и наследование в том же предложении. Как сказал Майкл Боргвардт, интерфейс не является определением, а аспектом.

Ответ 13

Фактически вы можете наследовать от нескольких конкретных классов, если они сами реализуют интерфейсы. innerclasses поможет вам достичь этого:

interface IBird {
    public void layEgg();
}

interface IMammal {
    public void giveMilk();
}

class Bird implements IBird{
    public void layEgg() {
        System.out.println("Laying eggs...");
    }
}

class Mammal implements IMammal {
    public void giveMilk() {
        System.out.println("Giving milk...");
    }
}

class Platypus implements IMammal, IBird {

    private class LayingEggAnimal extends Bird {}
    private class GivingMilkAnimal extends Mammal {}

    private LayingEggAnimal layingEggAnimal = new LayingEggAnimal();

    private GivingMilkAnimal givingMilkAnimal = new GivingMilkAnimal();

    @Override
    public void layEgg() {
        layingEggAnimal.layEgg();
    }

    @Override
    public void giveMilk() {
        givingMilkAnimal.giveMilk();
    }

}

код >

Ответ 14

Я не думаю, что они это делают.

Наследование - это определенно ориентированная на реализацию взаимосвязь между реализациями. Интерфейсы вообще не предоставляют никакой информации о реализации, а определяют тип. Чтобы иметь наследование, вам нужно специально наследовать некоторые поведения или атрибуты родительского класса.

Я считаю, что здесь где-то есть вопрос о роли интерфейсов и множественном наследовании, но я не могу найти его сейчас...

Ответ 15

На самом деле нет моделирования множественного наследования в Java.

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

Ответ 16

Если это имеет смысл в вашей объектной модели, вы, конечно, можете наследовать один класс и реализовать 1 или более интерфейсов.

Ответ 17

Бывают случаи, когда многократное наследование оказывается очень удобным и трудным для замены интерфейсами без написания большего количества кода. Например, есть приложения для Android, которые используют классы, полученные из Activity, и другие из FragmentActivity в том же приложении. Если у вас есть определенная функция, которую вы хотите использовать в общем классе, в Java вам придется дублировать код, а не позволять дочерним классам Activity и FragmentsActivity выводиться из одного класса SharedFeature. И плохое внедрение дженериков в Java не помогает ни потому, что написано следующее незаконно:

public class SharedFeature<T> extends <T extends Activity>

...
...

Ответ 18

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

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

Это пытается приблизиться к множественному наследованию. Что мы делаем - это реализовать несколько интерфейсов, здесь мы не расширяем (наследуем) что-либо. Класс внедрения - это тот, который будет добавлять свойства и поведение. Это не освобождает реализацию от родительских классов. Я бы просто сказал, что нет поддержки множественного наследования в java.

Ответ 19

Я хотел бы указать на то, что заставило меня позади, из С++, где вы можете легко наследовать многие реализации.

Наличие "широкого" интерфейса со многими методами означает, что вам придется реализовать множество методов в ваших конкретных классах, и вы не можете делиться ими легко через реализации.

Например:

interface Herbivore {
    void munch(Vegetable v);
};

interface Carnivore {
    void devour(Prey p);
}

interface AllEater : public Herbivore, Carnivore { };

class Fox implements AllEater {
   ... 
};

class Bear implements AllEater {
   ...
};

В этом примере Fox и Bear не могут использовать общую базовую реализацию для обоих методов интерфейса munch и devour.

Если базовые реализации выглядят так, мы, возможно, захотим их использовать для Fox и Bear:

class ForestHerbivore implements Herbivore
    void munch(Vegetable v) { ... }
};

class ForestCarnivore implements Carnivore
    void devour(Prey p) { ... }
};

Но мы не можем наследовать их обоих. Базовые реализации должны быть переменными-членами в классе, и определенные методы могут перенаправлять на это. То есть:

class Fox implements AllEater {
    private ForestHerbivore m_herbivore;
    private ForestCarnivore m_carnivore;

    void munch(Vegetable v) { m_herbivore.munch(v); }
    void devour(Prey p) { m_carnivore.devour(p); }
}

Это становится громоздким, если интерфейсы растут (т.е. более 5-10 методов...)

Лучшим подходом является определение интерфейса как агрегация интерфейсов:

interface AllEater {
    Herbivore asHerbivore();
    Carnivore asCarnivore();
}

Это означает, что Fox и Bear должны реализовать только эти два метода, а интерфейсы и базовые классы могут расти независимо от агрегированного интерфейса AllEater, который относится к классам реализации.

Меньше сочетается таким образом, если он работает для вашего приложения.

Ответ 21

Я также должен сказать, что Java не поддерживает множественное наследование.

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

Если вы реализуете интерфейс, существует нулевая вероятность того, что вы пропустите реализацию всех методов в каждом интерфейсе (Исключение: реализация по умолчанию методов интерфейса, введенных в Java 8) Итак, вы теперь полностью осознаете, что происходит с вещами, которые вы встроили в свой новый класс.

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

Если вам нужна дополнительная информация о интерфейсах Java, ознакомьтесь с этой статьей, http://www.geek-programmer.com/introduction-to-java-interfaces/