2009-01-20 4 views
11

Je l'interface suivante:Comment spécifier génériquement une liste Serializable

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

Avec cette interface, je ne peux pas définir une variable de type

Result<List<Integer>> 

parce que la liste ne sont pas sérialisable.

Cependant, si je change l'interface à ceci:

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

Il devient impossible de mettre en œuvre, avec la compilation de vérification, parce qu'il n'y a aucune garantie que T est sérialisable, et le point de l'ensemble de la classe est de stocker le résultat pour que je puisse le récupérer plus tard, éventuellement après un transfert sur internet. Ma question est la suivante: existe-t-il un moyen de déclarer une variable de sorte qu'elle soit de deux types ou existe-t-il un autre moyen de le faire que je ne vois pas? Alors, peut-être quelque chose comme:

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

Je suis en train de mettre autant de la charge de ce problème sur la mise en œuvre, afin que les consommateurs futurs de cette interface ne sont pas conscients du problème.

Merci pour votre aide!

Voici un exemple plus détaillé de ce que j'essaie de faire: J'appelle un serveur, Le résultat de ce que je veux stocker dans un objet de résultat, mais je ne veux pas avoir à faire face à la coulée. Ainsi, chaque méthode pouvant être appelée sur le serveur définira le type du résultat en utilisant des génériques. Cet objet résultat stockera également d'autres méta-données sur le résultat, par exemple, il y a peut-être trop d'informations à renvoyer. Dans la plupart des cas, je souhaite utiliser une liste, mais l'interface List n'est pas sérialisable, bien que la plupart des implémentations le soient. Donc, comment spécifier que le type utilisé doit être Serializable, mais permettre toujours une liste (et non une implémentation spécifique de List) à utiliser?

+0

Pouvez-vous clarifier ce que vous essayez de faire? Peut-être donner un plus grand exemple? –

+0

Vous devez savoir que même si T est marqué comme étant sérialisable, il peut toujours contenir une référence à un objet qui n'est pas sérialisable. Ainsi, il passera l'analyse statique des génériques mais échouera à l'exécution. – Patrick

+2

Vrai, mais c'est une erreur que le consommateur a faite, et pas un défaut dans mon code. Si un consommateur déclare quelque chose comme sérialisable, et ne suit pas les exigences de sérialisation, il n'y a rien que je puisse faire. – Megamug

Répondre

8

Vous devez déclarer votre type variable Result<? extends List<Integer>>.

La vérification de type sait que List n'est pas serializable, mais un sous-type de List peut être serializable.

Voici un exemple de code. L'implémentation de l'interface vient d'être effectuée avec des classes internes anonymes. Vous pouvez voir que le getResult retournera un List<Integer> sur le 2ème objet

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(); 

Edit: Fait l'exemple plus complet en mettant en œuvre une méthode d'interface void addResult(T input)

+0

Génial! Je commençais à penser qu'il n'y avait pas moyen de le faire. Merci! – Megamug

-1

Pensée initiale. Si vous envisagez d'utiliser la sérialisation pour tout type de stockage de données à long terme, ne le faites pas. La sérialisation n'est pas garantie pour fonctionner entre les invocations de la JVM.

Vous ne devriez probablement pas étendre Serializable sauf si vous ajoutez des fonctionnalités liées à la sérialisation d'objets. Au lieu de cela, votre classe qui implémente Result doit également implémenter Serializable.

+0

Je ne l'utilise pas pour le stockage de données à long terme.Désolé, quand j'ai dit "le but de la classe est de stocker le résultat", je voulais dire plus tard dans la même instance du programme. – Megamug

0

Si votre intention est d'utiliser le type de résultat pour les listes en général, et ce que vous voulez est de vous assurer que les éléments de la liste sont sérialisables, vous pouvez le définir comme ceci:

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

De cette façon , vous pouvez définir quelque chose comme:

Result<List<Integer>> r; 

Mais quelque chose comme ça ne compilerait pas:

Result<List<List>> r; 

Maintenant, si vous voulez utiliser le résultat pour, par exemple, Integer, et pour List, alors le type n'est pas requis pour être sérialisable, n'est-ce pas? Dans ce cas, je ne comprends pas vraiment quel est votre objectif.

+0

Il doit prendre en compte tout objet qui est sérialisable, pas seulement List. Il doit être sérialisable pour pouvoir être transféré entre le serveur et le client. – Megamug

+0

Si le type doit être sérialisable, il ne peut pas être List. Si vous souhaitez utiliser List, vous ne pouvez pas exiger qu'il soit sérialisable. Je pense que je ne vois pas quel genre de solution vous cherchez, désolé. –

+0

Il peut être une liste et être sérialisable. Par exemple, java.util.ArrayList. – Megamug

1

Vous pouvez simplement déclarer la variable comme Result<ArrayList<Integer>>. Tant que vous programmez à l'interface List, vous n'avez pas vraiment sacrifié la remplaçabilité.

j'allais aussi suggérer la création d'une nouvelle interface ListResult:

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

mais alors vous devez toujours déclarer la variable comme ListResult<ArrayList<Integer>>. Donc, j'irais la route la plus simple.

+0

Je ne veux pas forcer le serveur à spécifier l'implémentation qui sera retournée car il ne pourra pas être changé passivement. – Megamug

0

Vous genre de peut, je pense:

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); 
    } 
} 

Est-ce que laid enought pour regarder vous? Puis-je vous suggérer de ne pas appliquer l'implémentation Serializable en utilisant le système de type statique Java? C'est seulement une interface parce que les annotations n'étaient pas à l'époque. Ce n'est simplement pas pratique de l'appliquer. OTOH, vous pouvez l'appliquer en utilisant un vérificateur de type qui effectue une analyse statique dans un système fermé.

+0

Ce n'est pas tout à fait ce dont j'ai besoin car je ne peux pas supposer que c'est une liste. Cependant, quand je fais juste "V extends T & Serializable", je reçois une exception. Cela pourrait être un sujet pour une autre question si. – Megamug

0

La façon dont je fini par résoudre ce problème est d'utiliser ce que l'interface:

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

Ensuite, créez une implémentation pour chacun des différents types de collections ainsi qu'un pour tout objet.

Ainsi, par exemple, est ici ce que la classe ListResult ressemblerait à ceci:

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

Bien que l'interface List ne met pas en œuvre Serializable, tous les implémentations de Collection intégrées le font. Ceci est discuté dans les collections Implementations tutorial.

La FAQ de la collection de conception a une question "Why doesn't Collection extend Cloneable and Serializable?" qui explique pourquoi Sun l'a conçu sans étendre Serializable.

+0

Bon, je comprends le raisonnement derrière tout cela, mais dans ce cas, je devais m'assurer que la liste qui était utilisée était sérialisable. – Megamug

Questions connexes