2009-01-20 18 views
11

tengo la siguiente interfaz:Cómo especificar una lista genérica Serializable

public interface Result<T extends Serializable> extends Serializable{ 
    T getResult(); 
} 

Con esa interfaz, que no se puede definir una variable de tipo

Result<List<Integer>> 

porque Lista no es serializable.

Sin embargo, si cambio de la interfaz para esto:

public interface Result<T> extends Serializable{ 
    T getResult(); 
} 

Ahora se hace imposible poner en práctica, con la comprobación de tiempo de compilación, porque no hay ninguna garantía de que T es serializable, y el punto central de la clase es almacenar el resultado para poder recuperarlo más tarde, posiblemente después de una transferencia a través de Internet.

Mi pregunta es esta, ¿hay alguna manera de declarar una variable para que sea de dos tipos, o hay alguna otra forma de hacer esto que no estoy viendo? Por lo tanto, tal vez algo como:

(List<Integer> extends Serializable) value = new ArrayList(); 

Estoy tratando de poner la mayor parte de la carga de este problema sobre la aplicación, para que los futuros consumidores de esta interfaz no son conscientes del problema.

Gracias por su ayuda!

Aquí hay un ejemplo más detallado de lo que estoy tratando de hacer: Estoy llamando a un servidor, El resultado del cual quiero almacenar en un objeto de resultado, pero no quiero tener que lidiar con el casting. Por lo tanto, cada método que se pueda llamar en el servidor definirá el tipo de resultado mediante el uso de genéricos. Este objeto de resultado también almacenará otros metadatos sobre el resultado, por ejemplo, tal vez haya demasiada información para devolver. En muchos casos quiero usar una lista, pero la interfaz de la Lista no es serializable, aunque muchas de las implementaciones sí lo están.

Entonces, ¿cómo especifico que el tipo utilizado debe ser Serializable, pero aún permitir el uso de una Lista (y no una implementación específica de la Lista)?

+0

¿Puede aclarar lo que está tratando de hacer? Tal vez dar un ejemplo más grande? –

+0

Debe saber que incluso si T está marcado como serializable, aún puede contener una referencia a un objeto que no es serialiazble. Por lo tanto, pasará el análisis estático de genéricos pero fallará en el tiempo de ejecución. – Patrick

+2

Cierto, pero ese es un error que cometió el consumidor y no un defecto en mi código. Si un consumidor declara algo como serializable y luego no sigue los requisitos de ser serializable, no hay nada que pueda hacer. – Megamug

Respuesta

8

Es necesario declarar el tipo de variable como Result<? extends List<Integer>>.

La comprobación de tipos sabe que no es Listserializable, pero un subtipo de List puede ser serializable.

Aquí hay algunos ejemplos de código. La implementación de la interfaz acaba de hacerse con clases internas anónimas. Se puede ver que la getResult devolverá un List<Integer> en el segundo objeto

Result<Integer> res = new Result<Integer>() { 

     Integer myInteger; 

     private static final long serialVersionUID = 1L; 

     @Override 
     public Integer getResult() { 
      return myInteger; 
     } 

     @Override 
     public void addResult(Integer input) { 
      this.myInteger = input; 
     } 
    }; 

    Integer check = res.getResult(); 


    Result<? extends List<Integer>> res2 = new Result<ArrayList<Integer>>() { 

     ArrayList<Integer> myList; 

     private static final long serialVersionUID = 1L; 

     @Override 
     public ArrayList<Integer> getResult() { 
      return myList; 
     } 

     @Override 
     public void addResult(ArrayList<Integer> input) { 
      this.myList = input; 
     } 

    }; 

    List<Integer> check2 = res2.getResult(); 

Editar: Hecho el ejemplo más completo mediante la implementación de un método void addResult(T input) interfaz

+0

¡Impresionante! Estaba empezando a pensar que no había forma de hacerlo. ¡Gracias! – Megamug

-1

Pensamiento inicial. Si planea utilizar la serialización para cualquier tipo de almacenamiento de datos a largo plazo, no lo haga. No se garantiza que la serialización funcione entre invocaciones de la JVM.

Probablemente no deba extender Serializable a menos que esté agregando funciones relacionadas con la serialización de Objetos. En cambio, su clase que implemente el Resultado también debería implementar Serializable.

+0

No lo estoy usando para el almacenamiento de datos a largo plazo.Lo siento, cuando dije "el objetivo de la clase es almacenar el resultado", quise decir más adelante en la misma instancia del programa. – Megamug

0

Si su intención es utilizar el tipo de resultado para las listas en general, y lo que quiere es asegurarse de que los elementos de la lista son serializable, se podría definir así:

public interface Result<T extends List<? extends Serializable>> {} 

De esa manera , se podría definir algo como:

Result<List<Integer>> r; 

Pero algo como esto no sería compilar:

Result<List<List>> r; 

Ahora, si desea usar el resultado para, digamos, Entero y para Lista, entonces no es necesario que el tipo sea serializable, ¿verdad? En ese caso, realmente no entiendo cuál es tu objetivo.

+0

Necesita contabilizar cualquier objeto que sea serializable, no solo List. Necesita ser serializable para que pueda ser transferido entre el servidor y el cliente. – Megamug

+0

Si el tipo necesita ser serializable, entonces no puede ser List. Si desea usar List, no puede exigir que sea serializable. Creo que no veo qué tipo de solución estás buscando, lo siento. –

+0

Puede ser una lista y ser serializable. Por ejemplo, java.util.ArrayList. – Megamug

1

Simplemente puede declarar la variable como Result<ArrayList<Integer>>. Mientras siga programando en la interfaz List, realmente no habrá sacrificado la capacidad de reemplazo.

Iba a sugerir también la creación de una nueva interfaz ListResult:

public interface ListResult<T extends Serializable & List<E extends Serializable>> 
     implements Result<T> { 
    T getResult(); 
} 

pero entonces todavía tendría que declarar la variable como ListResult<ArrayList<Integer>>. Así que iría por la ruta más simple.

+0

No quiero obligar al servidor a especificar la implementación que se devolverá porque no podrá cambiarse pasivamente. – Megamug

0

De alguna manera puedo, creo:

public class Thing<T extends Serializable> implements Serializable { 
    private static class Holder<V extends Serializable> { 
     private final V value; 
     private Holder(V value) { 
      this.value = value; 
     } 
    } 
    private Holder<? extends List<T>> holder; 
    private <V extends List<T> & Serializable> void set(V value) { 
     holder = new Holder<V>(value); 
    } 
} 

Cómo se ve feo lo suficientemente para usted?

¿Puedo sugerirle que no intente forzar la implementación de Serializable utilizando el sistema de tipo estático de Java? Es solo una interfaz porque las anotaciones no se trataban en ese momento. Simplemente no es práctico hacer cumplir. OTOH, podrías aplicarlo usando un verificador de tipos que realice análisis estáticos en un sistema cerrado.

+0

Esto no es exactamente lo que necesito porque no puedo suponer que se trata de una lista. Sin embargo, cuando hago "V extends T & Serializable", recibo una excepción. Sin embargo, este podría ser un tema para otra pregunta. – Megamug

0

La forma en que terminó la solución de este problema es utilizar esto como la interfaz:

public interface Result<T> extends Serializable{ 
    T getResult(); 
} 

A continuación, cree una implementación para cada uno de los diferentes tipos de colecciones, así como uno para cualquier objeto.

Así, por ejemplo, esto es lo que la clase ListResult se vería así:

public class ListResult<T> implements Result<List<T>>{ 
    public List<T> getResult(){ 
     //return result 
    } 

    public <V extends List<T> & Serializable> void setResult(V result){ 
     //store result 
    } 
} 
3

Aunque la interfaz de lista no implementa Serializable, todos las implementaciones de colecciones incorporadas sí. Esto se discute en las colecciones Implementations tutorial.

The Collections Design tiene una pregunta "Why doesn't Collection extend Cloneable and Serializable?" que explica por qué Sun la diseñó sin extender Serializable.

+0

Correcto, entiendo el razonamiento detrás de todo, pero en este caso necesitaba asegurarme de que la Lista que se estaba utilizando fuera serializable. – Megamug

Cuestiones relacionadas