2012-11-14 10 views
27

ho pensato ereditarietà multipla è sempre stato illegale in Java, ma questo codice compila:ereditarietà multipla su Java interfaccia

public interface A { 
    void a(); 
} 

public interface B { 
    void b(); 
} 

public interface AB extends A, B { 
} 

Sarebbe avere un'interfaccia vuota come AB essere considerata una cattiva pratica? C'è un modo per ottenere qualcosa di simile evitando l'interfaccia vuota (usando generici o altro)?

Nota: non sto chiedendo come simulare l'ereditarietà multipla tramite interfacce. Mi rendo conto che potrei fare quanto segue:

public class AbImpl implements A, B { 
    public void a() {} 
    public void b() {} 
} 

Per varie ragioni ho bisogno di un'interfaccia che abbia entrambi i metodi.

+0

Il tuo primo esempio fornisce un collegamento che è sostanzialmente equivalente al secondo esempio. Non c'è niente di sbagliato nel farlo. –

risposta

25

L'ereditarietà multipla delle implementazioni non è consentita. I componenti possono ereditare più interfacce, però.

Ereditare più interfacce non è problematico, dal momento che stai semplicemente definendo nuove firme di metodo da implementare. È l'ereditarietà di più copie di funzionalità tradizionalmente considerate come causa di problemi o, per lo meno, confusione (ad esempio, lo diamond of death).

+0

Grazie per aver menzionato il diamon di deat;) – servatj

8

Un'interfaccia può estendere una o più altre interfacce. Puoi anche implementare più di un'interfaccia nelle tue classi. È legale perché l'interfaccia è solo un contratto - non c'è implementazione. Stai semplicemente definendo un contratto per ciò che una classe è in grado di fare, senza dire nulla su come la classe lo farà.

4

L'implementazione di interfacce non è "ereditarietà", ovvero quando si si estende a una classe.

L'implementazione di interfacce viene utilizzata per dichiarare che una classe "assomiglia" a qualcosa, mentre le classi di estensione vengono utilizzate per dichiarare che una classe "è un" qualcosa.

Va bene "sembrare" più cose, ma non "essere" più cose.


c'è niente di sbagliato con avere interfacce vuote che si estendono più interfacce come un modo di raccogliere un insieme di interfacce in una singola interfaccia per trasmettere un ampio, ma riutilizzati, API.

0

In this related question, Jay fornisce una risposta a questo. La differenza sta specificando l'implementazione rispetto all'interfaccia.

Il problema con l'implementazione si verifica solo quando due funzioni hanno lo stesso nome. Questo perché non c'è una scelta ovvia alla domanda "Quale implementazione di f() uso?" con più implementazioni.

Il problema non si verifica con due interfacce con lo stesso nome di funzione perché non è necessario effettuare questa selezione. Piuttosto, ti è solo richiesto di implementare la tua versione della funzione a portata di mano.

Ad esempio, possiamo osservare una controparte che è does allow multiple inheritance - C++. Questo link spiega bene le cose e fornisce alcuni esempi di codice/immagine. Una cosa da notare è che dal momento che è necessario esplicitare in modo esplicito a quale classe appartiene una funzione, è possibile attenuare facilmente il problema in C++.

In Java, tuttavia, non dobbiamo mai farlo (poiché ci sono solo metodi che sono collegati agli oggetti, se lo si desidera), di conseguenza non esiste un metodo per definire la portata della chiamata. Le uniche opzioni che dobbiamo fare riferimento a una classe genitore sono l'utilizzo della parola chiave super o l'uso di una funzione static. Di conseguenza, non ci sarebbe una chiara opzione per risolvere questo problema in Java, escludendo ulteriori modifiche al sistema, con scarso guadagno.

0

Prova questa, che richiede Java 8.

Basta copiare e salvare il file in Stateful.java.

E 'disponibile anche qui: 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; 
       } 
     } 
     /************************************************************************************/ 

}