2012-11-14 6 views
27

Ich dachte, Mehrfachvererbung in Java immer illegal war, aber dieser Code kompiliert:Mehrfachvererbung auf Java-Schnittstellen

public interface A { 
    void a(); 
} 

public interface B { 
    void b(); 
} 

public interface AB extends A, B { 
} 

wäre eine leere Schnittstelle mit wie AB eine schlechte Praxis in Betracht gezogen werden? Gibt es eine Möglichkeit, etwas Ähnliches zu erreichen und dabei die leere Schnittstelle zu vermeiden (mit Generika oder anderweitig)?

Hinweis: Ich frage nicht, wie man die Mehrfachvererbung über Schnittstellen simuliert. Ich weiß, ich könnte Folgendes tun:

Aus verschiedenen Gründen brauche ich eine Schnittstelle, die beide Methoden hat.

+0

Ihr erstes Beispiel stellt eine Verknüpfung, die im Wesentlichen äquivalent zu dem zweiten Beispiel. Es ist nichts falsch daran, dies zu tun. –

Antwort

25

Mehrfache Vererbung von Implementierungen ist nicht erlaubt. Komponenten können jedoch mehrere Schnittstellen erben.

Das Erben mehrerer Schnittstellen ist nicht problematisch, da Sie einfach nur neue Methodensignaturen definieren, die implementiert werden sollen. Es ist die Vererbung von mehreren Kopien von Funktionalität, die traditionell als Probleme oder zumindest als Verwirrung angesehen werden (z. B. die diamond of death).

+0

Danke für die Erwähnung der Diamon deat;) – servatj

8

Eine Schnittstelle kann eine oder mehrere andere Schnittstellen erweitern. Sie können in Ihren Klassen auch mehr als eine Schnittstelle implementieren. Es ist legal, weil Schnittstelle nur Vertrag ist - es gibt keine Implementierung. Sie definieren einfach einen Vertrag für das, was eine Klasse tun kann, ohne etwas darüber zu sagen, wie die Klasse das macht.

4

Implementieren von Schnittstellen ist nicht "Vererbung", was ist, wenn Sie eine Klasse erweitern.

Das Implementieren von Schnittstellen wird verwendet, um zu deklarieren, dass eine Klasse "wie etwas aussieht", während das Erweitern von Klassen verwendet wird, um zu deklarieren, dass eine Klasse "ein" etwas ist.

Es ist in Ordnung, mehrere Dinge "aussehen", aber nicht "sein" mehrere Dinge.


Es gibt nichts Falsches daran, leere Schnittstellen zu haben, die mehrere Schnittstellen erweitern, um eine Reihe von Schnittstellen in einer einzigen Schnittstelle zu sammeln, um eine breitere, aber wiederverwendbare API zu vermitteln.

0

In this related question bietet Jay eine Antwort darauf. Der Unterschied besteht darin, die Implementierung gegenüber der Schnittstelle anzugeben.

Das Problem mit der Implementierung tritt nur auf, wenn zwei Funktionen denselben Namen haben. Dies liegt daran, dass es keine offensichtliche Wahl für die Frage "Welche Implementierung von f() verwende ich?" mit mehreren Implementierungen.

Das Problem tritt nicht bei zwei Schnittstellen mit demselben Funktionsnamen auf, da diese Auswahl nicht erforderlich ist. Sie müssen lediglich eine eigene Version der Funktion implementieren.

Als Beispiel können wir ein Gegenstück betrachten, das does allow multiple inheritance - C++. Dieser Link erklärt die Dinge gut und bietet einige Code-/Image-Beispiele. Eine Sache zu beachten ist, dass Sie, da Sie explizit angeben müssen, zu welcher Klasse eine Funktion gehört, das Problem in C++ leicht beheben können.

In Java jedoch müssen wir dies wirklich nie tun (da es nur Methoden gibt, die an Objekte angehängt sind, wenn Sie so wollen). Daher haben Sie keine Methode, um den Aufruf einzugrenzen. Die einzigen Optionen, die wir auf eine Elternklasse beziehen müssen, sind das Schlüsselwort super oder die Verwendung einer static-Funktion. Daher gibt es keine klare Option, dies in Java zu lösen, da zusätzliche Änderungen am System für wenig Nutzen ausgeschlossen sind.

0

dies versuchen, es erfordert Java 8.

Kopieren Sie einfach und die Datei in Stateful.java speichern.

Es ist auch hier verfügbar: https://bitbucket.org/momomo/opensource/src/e699d8da450897b5f6cd94a5d329b3829282d1d6/src/momomo/com/Stateful/Stateful.java?at=default

/************************************************************************************************************************************** 
* Copyright(C) 2014, Mo Enterprises Inc.                        * 
* All rights reserved.                            * 
* Mo Enterprises Inc Opensource License 'MoL1'.                      * 
*                                 * 
* (1) Use of this source code, wether identical, changed or altered is allowed, for both commercial and non-commercial use.   * 
*                                 * 
* (2) This source code may be changed and altered freely to be used only within your entity/organisation, given that a notice of all * 
*  changes introduced are listed and included at the end of a copy of this exact copyright notice, including the name and date of * 
*  the entity/organization that introduced them.                     * 
*                                 * 
* (3) The redistribution or publication to the public of this source code, if changed or altered, is striclty prohibited using any * 
*  medium not owned, and/or controlled by Mo Enterprises Inc unless a written consent has been requested and recieved by   * 
*  representatives of Mo Enterprises Inc.                       * 
*                                 * 
* (4) The distribution of any work to the public derived through the use of this source code, wether identical, changed or altered, * 
*  is allowed, as long as it in full compliance of (3).                   * 
*                                 * 
* (5) Mo Enterprises Inc considers the techniques and design patterns employed in this source code as unique and making the   * 
*  redistribution of this source code with altered names, and/or a rearrangement of code as a severe breach of the copyright law * 
*  and this license. Mo Enterprises Inc reserves all rights to puruse any and all legal options.         * 
*                                 * 
* (6) All copies of this source code, wether identical, changed/altered must include this entire copyright notice, list all changes * 
*  made including the name and date of the entity/organization that introduced them, as wel as the following disclaimer:   * 
*                                 * 
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND            * 
*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED             * 
*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE               * 
*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR            * 
*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES             * 
*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;             * 
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND             * 
*  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT              * 
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS             * 
*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                 * 
*                                 * 
* Please contact us on [email protected]{at}momomo.com if you have an improvement to this source code you'd like to contribute.   * 
* We'll make sure to include your name and/or organisation as a contributor if accepted.            * 
**************************************************************************************************************************************/ 

import java.util.IdentityHashMap; 
import java.util.Map; 

/** 
* @Author Mo. Joseph 
* 
* Consider memory leakage usage. 
* None of the public methods below should be used outside of the interface extending Stateful! 
*/ 
@SuppressWarnings("unchecked") 
public interface Stateful { 
     /** 
     * @Private access only! Strict enforcement, otherwise risks for memomry leaks! 
     */ 
     static final Map<Stateful, IdentityHashMap<Class<State>, State>> STATES = new WeakIdentityHashMap<>(); 

     /** 
     * @Protected access only! Strict enforcement, otherwise risks for memomry leaks! 
     * 
     * Note, this method can not be generified! 
     * If so, then it will conflict when a class implements several Stateful interfaces. 
     */ 
     default <Y extends Stateful, T extends State<Y>> T $(Class<T> clazz) { 
       synchronized (this) { 
         IdentityHashMap<Class<State>, State> map = STATES.get(this); 
         if (map == null) { 
           STATES.put(this, map = new IdentityHashMap<>()); 
         } 

         State state = map.get(clazz); 
         if (state == null) { 
           try { 
             map.put(cast(clazz), state = clazz.newInstance()); 
           } catch (Throwable e) { 
             throw new RuntimeException(e); 
           } 
         } 
         return (T) state; 
       } 
     } 

     /** 
     * @Protected access only! Strict enforcement, otherwise risks for memomry leaks! 
     * May only be extended from within an interface that implements Stateful. 
     */ 
     static interface State<Y extends Stateful> {} 

     /** 
     * @Private 
     * Util method for casting used here. Simple casting won't work for some reason. 
     */ 
     static <T>T cast(Object obj){ 
       return (T) obj; 
     } 



     /******************************************************************************* 
     * Example code below: 
     *******************************************************************************/ 
     public static void main(String[] args) { 
       Person mo = new Person(); 
       mo.setName("Mo. Joseph"); 
       mo.setStreet("Mansion Street 1"); 
       System.out.println(mo.getName()); 
       System.out.println(mo.getStreet()); 

       Pet garfield = new Pet(); 
       garfield.setName("Garfield"); 
       System.out.println(garfield.getName()); 

       Person santa = new Person(); 
       santa.setName("Santa"); 
       santa.setStreet("North Pole Street 1"); 
       System.out.println(santa.getName()); 
       System.out.println(santa.getStreet()); 

       mo.setName("mo"); 
       System.out.println(mo.getName()); 
       System.out.println(santa.getName()); 
       System.out.println(garfield.getName()); 
       System.out.println(santa.getStreet()); 
     } 

     public static class Person implements Named, Address { 

     } 

     public static class Pet implements Named { 

     } 

     public static interface Named extends Stateful { 
       static class State implements Stateful.State<Named> { 
         private String name; 
       } 

       public default void setName(String name) { 
         $(State.class).name = name; 
       } 

       public default String getName() { 
         return $(State.class).name; 
       } 
     } 

     public static interface Address extends Stateful { 
       static class State implements Stateful.State<Address> { 
         private String street; 
       } 

       public default void setStreet(String street) { 
         $(State.class).street = street; 
       } 

       public default String getStreet() { 
         return $(State.class).street; 
       } 
     } 
     /************************************************************************************/ 

}