2008-11-25 9 views
15

¿Es posible convertir un objeto en Java en un tipo genérico combinado?¿Cómo debo convertir Java genérico con múltiples límites?

tengo un método como:

public static <T extends Foo & Bar> void doSomething(T object) { 
    //do stuff 
} 

llamada a este método no es problema si tengo una clase que implementa dos interfaces (Foo & bar).

El problema es que cuando necesito llamar a este método, el objeto que necesito pasar se recibe como java.lang.Object y necesito convertirlo para hacer feliz al compilador. Pero no puedo entender cómo hacer esto.

edición:

El problema radica en una función como esta:

public void problemFunction (Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     doSomething((Problematic cast) o); 
    } 
} 

}

Respuesta

12

Por desgracia, no hay reparto legal que usted puede hacer para satisfacer a esta situación. Debe haber un único tipo conocido para implementar todas las interfaces que necesita como límites, para que pueda convertirlo. Puede ser un tipo que cree para ese fin, o algún tipo existente.

interface Baz extends Foo, Bar { } 

public void caller(Object w) { 
    doSomething((Baz) w); 
} 

Si se conocen otros tipos, como Baz, para cumplir con los límites, se puede probar para aquellos tipos, y tienen una sucursal en su interlocutor que llama doSomething con un reparto de esos tipos. No es lindo.

También podría usar la delegación, creando su propia clase Baz que cumpla con los límites requeridos por doSomething. A continuación, ajuste el objeto que se le pasa en una instancia de su clase Baz y pase ese contenedor al doSomething.

private static class FooBarAdapter implements Foo, Bar { 
    private final Object adaptee; 
    FooBarAdapter(Object o) { 
    adaptee = (Foo) (Bar) o; 
    } 
    public int flip() { return ((Foo) adaptee).flip(); } 
    public void flop(int x) { ((Foo) adaptee).flop(x); } 
    public void blort() { ((Bar) adaptee).blort(); } 
} 

public void problemFunction (Object o) { 
    doSomething(new FooBarAdapter(o)); 
} 
+0

Buena idea. Lo usé de una manera ligeramente diferente. Prefiero el FooBarAdapter para llegar a los objetos con los 2 tipos diferentes. El == se puede usar para verificar si es el mismo objeto (no es obligatorio). De esta manera, es una verificación de tipo de tiempo de compilación. –

+1

Combiné este patrón delegado anónimo/named method method classes para "lanzar" un objeto que conozco para extender/implementar un conjunto de clases e interfaces para los requisitos vinculados. Ver la respuesta de Jon: http://stackoverflow.com/a/9514406/910718 –

+0

Y esta parece ser la limitación del lenguaje Java porque en Scala corriendo en la misma JVM, esto es fácil como o.asInstanceOf [Foo con barra] –

-1

Como solución alternativa, puede definir otra interfaz FooBar que amplíe Foo y Bar y haga que su clase la implemente. Ni siquiera tiene que ser una interfaz de nivel superior - se puede declarar en privado si no quieren el desorden o modernizar el resto de su código:

private interface FooBar extends Foo, Bar {} 
public void problemFunction (Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     doSomething((FooBar) o); 
    } 
} 
+1

Creo que esto no funcionará, ya que no hay garantía de que el o realmente tenga "implementos FooBar". No creo que Java lo asuma. – ArtB

+0

@ArtB La respuesta dice "y haz que tu clase lo implemente". – cquezel

7
public static <T extends Foo & Bar> void doSomething(T object) 

Esto parece denotar que realizaría más de una operación en el objeto en cuestión.

Me atrevería a decir que si las operaciones deseadas que está realizando en el objeto son lo suficientemente distintas para ser separadas a través de las interfaces, entonces son lo suficientemente distintas como para merecer sus propios métodos.

Es probable que pueda reestructurar este código para llamar a métodos separados para realizar la operación deseada. Esto puede terminar haciendo que toda la operación sea más clara desde la perspectiva del cliente.

En lugar de:

public void problemFunction (Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     doSomething((Problematic cast) o); 
    } 
} 

Se convierte en:

public void problemFunction(Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     fooifySomething((Foo) o); 
     baratizeSomething((Bar) o); 
    } 
} 
+1

LMAO fooify, eso es nuevo para mí xD – Goodwine

5

Es posible "up-fundido" a un tipo de unión, por los medios horribles de que codifica el tipo de unión en el parámetro de tipo de un método; para su ejemplo, puede escribir

private <Q extends Foo & Bar> Q upcast(final Object in) { 
    return (Q) in; 
} 

// ... elsewhere... 

if (myObject instanceof Foo && myObject instanceof Bar) { 
    doSomething(upcast(myObject)); 
} 
+0

Gracias. La única molestia es que genera un elenco sin marcar. Sin embargo, utilicé una versión modificada que toma Foo en lugar de Object y comprueba que implementa Bar y luego regresa con el molde como lo ha hecho de lo contrario lanzando una ClassCastException. –

14

Java 8 introduce la posibilidad de casting with additional bounds. Puede lanzar Object como class con interfaces múltiple (o solo como interfaces múltiple).

Así que esto:

doSomething((Problematic cast) o); 

simplemente se vuelve a esto:

doSomething((Foo & Bar) o); 
+0

Lea acerca de esto recientemente ty para la actualización – pvgoddijn

Cuestiones relacionadas