2012-04-02 15 views
9

Se ho:È possibile creare raccolte Java sicure per tipo i cui membri implementano semplicemente più interfacce?

interface A{ void a(); } 
interface B{ void b(); } 

posso Hava un metodo generico come questo:

class C { 
    <T extends A & B> void c(T t) { 
     t.a(); 
     t.b(); 
    } 
} 

ma non posso Hava una raccolta generica come questa:

class D{ 
    List<? extends A & B> l; 
} 

lo so che potrei creare un'interfaccia vuota E che estenda sia A che B, e abbia una lista che contiene E ... ma preferirei lasciare le mie classi segnate solo con A e B, e non avere un E. T il suo è ancora più problematico quando ci sono molti altri A e B che possono essere combinati in 2^modi.

Preferirei essere in grado di definire un tipo al volo, come unione di interfacce, e fare in modo che le collezioni riconoscano gli oggetti che implementano tutte le interfacce come istanze di quel tipo.

C'è un modo per farlo in Java? Sono aperto a qualsiasi tipo di lavoro o hackeraggio a questo punto per evitare di creare una nuova interfaccia e taggare le mie classi con esso, così che possano vivere insieme in una raccolta. Oppure, se qualcuno potesse chiarire per me perché questo è impossibile, sarebbe ugualmente apprezzato.

+0

Intendi e * l'intersezione * di interfacce, non è vero? – Saintali

+0

Sono quasi certo che intendo un'unione di interfacce. Probabilmente stai pensando a come ci sia un diverso insieme di classi (che si spera non disgiunte) che implementano ciascuna interfaccia. Quindi l'insieme di classi che implementa l'unione delle interfacce è l'intersezione degli insiemi sopra descritti. –

risposta

9
public class Foo<T extends A & B> { 
    private List<T> list; 
    //getters, setters, etc. 
} 
+0

(Questo ora consente 'Foo l;' in 'D'.) –

+1

Vedo che' Foo 'può essere dichiarato in' D', ma non come istanziarlo ... Dovrei aggiungere che ho modificato la domanda in modo che la soluzione dovrebbe essere sicura. Altrimenti, questo potrebbe essere fatto con 'List's raw dall'inizio. –

0

Come Jeffrey ha anche detto in qualche modo, è necessario parametrizzare la classe D:

class D<T extends A & B> { 
    List<T> l; 

    /** 
    * this is just a method for the sake of example 
    */ 
    public T getSomeMember() { 
     return l.iterator().next(); 
    } 
} 

questo modo si stanno rimandando la scelta del tipo effettivo T al metodo che in realtà insntatiates D. Se tali informazioni non sono disponibili nemmeno a quel punto si dovrà parametrizzare quel metodo anche con <T extends A & B>:

private <T extends A & B> 
void doSomething() { 
    D<T> d = new D<T>(); 

    T v1 = d.getSomeMember(); 
    A v2 = d.getSomeMember(); 
    B v3 = d.getSomeMember(); 
} 

Se c'è un campo di tipo D in qualche classe, poi quella classe deve conoscere il tipo effettivo che extends A & B , o essere esso stesso parametrizzato se non lo fa. In linea di principio, il parametro type viene propagato fino a quando non si conosce il tipo effettivo.

Attenzione che questo processo rischia di diventare ingestibile per i codici di grandi dimensioni. Può anche risultare in un codice brutto, ma ovviamente dipende dalla tua concezione estetica.

+0

Il punto è che voglio evitare di avere un tipo 'T' (che sarebbe l'interfaccia' E' dalla domanda originale). Vorrei consentire tutto ciò che implementa entrambi gli elementi "A & B" nella raccolta, e nulla che non li implementa entrambi. Non voglio richiedere ai membri della collezione di avere qualcosa in comune, tranne che entrambi implementano "A & B". (O il motivo è impossibile ...) –

Problemi correlati