web-dev-qa-db-fra.com

Sécurité des types: conversion non vérifiée de l'objet vers la liste de tableaux <MyVariable>

Voici une partie d'un programme qui envoie une ArrayList d'un serveur à un client. Je souhaite supprimer l'avertissement concernant la dernière ligne de ce code:

Code client:

Socket s;
(...)
// A server is sending a list from the other side of the link.
ois = new ObjectInputStream(s.getInputStream());
MyList = (ArrayList<MyVariable>) ois.readObject();

MyVariable est une classe Java avec certains attributs. Le serveur crée une liste de tableaux et la remplit avec des variables MyVariable en tant qu'éléments. Ensuite, il envoie la liste complète au client.

Je voudrais savoir pourquoi j'ai un avertissement là-bas et comment coder parfaitement afin d'avoir 0 avertissements. Si c'est possible, je voudrais éviter d'utiliser "@SuppressWarnings (" non coché ")". ;)

Merci,

Luis

27
luisgomezcaballero

Essaye ça

Object obj = ois.readObject();
// Check it's an ArrayList
if (obj instanceof ArrayList<?>) {
  // Get the List.
  ArrayList<?> al = (ArrayList<?>) obj;
  if (al.size() > 0) {
    // Iterate.
    for (int i = 0; i < al.size(); i++) {
      // Still not enough for a type.
      Object o = al.get(i);
      if (o instanceof MyVariable) {
        // Here we go!
        MyVariable v = (MyVariable) o;
        // use v.
      }
    }
  }
}
21
Elliott Frisch

Il est impossible d'éviter cet avertissement. readObject() renvoie un objet. Vous devez le lancer. Et la conversion vers un type générique générera toujours un tel avertissement.

Si vous voulez rendre votre code aussi propre que possible, ce qui est une bonne idée, vous devez respecter les conventions de dénomination Java cependant, et faire en sorte que les noms de variables commencent par une lettre minuscule).

13
JB Nizet

Je n'aime pas ça, mais vous pouvez avoir un conteneur (sorte d'alias ou typedef):

// add "implements Serializable" in your case
private static class MyVariableList {
    public List<MyVariable> value;
}

Et utilisez plutôt MyVariableList. De cette façon, vous fournissez explicitement suffisamment d'informations au compilateur pour effectuer une vérification de type lors de l'exécution.

2
wonder.mice

Je rencontrais un problème similaire à OP et j'ai trouvé une bonne solution avec une combinaison de commentaires de @VGR et Java 1.8 méthode pour les tableaux.

Je vais fournir ma réponse en termes de question de OP, donc elle est générique et j'espère aider les autres:

  1. Au lieu de renvoyer une collection (liste), renvoyez un tableau à partir du serveur. Collection secrète dans un tableau à l'aide des éléments suivants du code côté serveur:

    myVariableList.toArray(new MyVariable[0]);

    Si les performances sont un problème avec ci-dessus, les éléments suivants peuvent être utilisés, de sorte que le tableau n'a pas besoin d'être redimensionné:

    myVariableList.toArray(myVariableList.size());

  2. Côté client, convertissez le tableau d'objets en un tableau de la classe MyVariable.

    Ceci est spécifique à Java 8.

    MyVariable[] myVarArr = Arrays.stream(ois.readObject()).toArray(MyVariable[]::new);

  3. Ensuite, convertissez enfin Array en Collection (liste).

    List<MyVariable> myList = Arrays.asList(myVarArr);

Merci.

1
abhishek

J'ai également rencontré une situation similaire et j'ai pu la résoudre. Ma solution, appliquée à l'exemple de l'OP est la suivante:

myList = (ArrayList<Someclass>) Arrays.asList( (Someclass[]) ois.readObject() );

J'ai changé les conventions de dénomination (comme suggéré par quelqu'un, déjà) en standard Java (les objets commencent par des caractères minuscules) et j'ai renommé la classe MyVariable en Someclass pour le rendre explicite, que cela s'applique vraiment à n'importe quelle classe (et pas seulement aux variables). Je suppose également que l'objet correspondant à myList du côté serveur de type ArrayList<Someclass> a été écrit dans le flux en tant que tableau Someclass[]. Notez que cela est facile à faire et analogue à la première partie de ce qu'abhishek a déjà suggéré, mais ma solution diffère sur la dernière étape dans la mesure où:

  1. J'évite d'appeler Arrays.stream
  2. Il est plus facile à lire et rapidement perçu comme un cast simple (sans autre logique) et checked (ne générant pas d'avertissement).
0
javaGeek