2012-04-02 8 views
9

Si tengo:¿Es posible crear colecciones de Java seguras de tipo cuyos miembros simplemente implementen varias interfaces?

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

puedo hava un método genérico de esta manera:

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

pero no puedo hava una colección genérica como esto:

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

que sé que podría hacer una interfaz E vacía que amplíe tanto A como B, y que tenga una Lista que contenga E ... pero preferiría dejar mis clases marcadas con solo A y B, y no tener que tener una E. Esto es aún más problemático cuando hay muchas más A y B que se pueden combinar de 2 maneras.

Prefiero ser capaz de definir un tipo sobre la marcha, como una unión de interfaces, y hacer que las colecciones reconozcan objetos que implementan todas las interfaces como instancias de ese tipo.

¿Hay alguna manera de hacer esto en Java? Estoy abierto a cualquier tipo de trabajo o pirateo en este punto para evitar crear una nueva interfaz y etiquetar mis clases con ella, solo para que puedan vivir juntas en una colección. O, si alguien puede aclararme por qué esto es imposible, eso sería igualmente apreciado.

+0

Te refieres a * intersección * de interfaces, ¿no es así? – Saintali

+0

Estoy bastante seguro de que me refiero a una unión de interfaces. Probablemente estés pensando en cómo hay un conjunto de clases diferentes (afortunadamente no disjuntas) que implementan cada interfaz. Entonces, el conjunto de clases que implementa la unión de las interfaces es la intersección de los conjuntos descritos anteriormente. –

Respuesta

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

(Esto ahora permite 'Foo l;' en 'D'.) –

+1

Veo que' Foo 'se puede declarar en' D', pero no cómo crear una instancia ... Debo agregar que modifiqué la pregunta para que la solución sea segura. De lo contrario, esto podría hacerse con Raw 'List's desde el principio. –

0

Como Jeffrey también dijo que de alguna manera, tiene que parametrizar la clase 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(); 
    } 
} 

esta manera usted está aplazando su elección del tipo real T al método que en realidad insntatiates D. Si esa información no está disponible incluso en ese momento se le tiene que parametrizar ese método también 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(); 
} 

Si hay un campo de tipo D de alguna clase, entonces esa clase debe conocer el tipo real que extends A & B , o se parametrizará si no lo hace. En principio, propagas el parámetro de tipo hasta que conozcas el tipo real.

Tenga en cuenta que es probable que este proceso sea inmanejable para códigos grandes. También puede dar como resultado un código feo, pero por supuesto que depende de su concepción de la estética.

+0

El punto es que quiero evitar tener un tipo 'T' (que sería la interfaz' E' de la pregunta original). Me gustaría permitir que cualquier cosa que implemente tanto 'A & B' en la colección, y nada que no implemente ambos. No quiero exigir a los miembros de la colección que tengan algo en común, excepto que ambos implementan 'A & B'. (O la razón por la que esto es imposible ...) –

Cuestiones relacionadas