Siguranță de tip: Turnare necontrolată de la Object la ArrayList (Programare, Java, Arraylist, Turnare, Avertismente, Unchecked Cast)

luisgomezcaballero a intrebat.

Iată o parte a unui program care trimite un ArrayList de la un server la un client. Vreau să elimin avertismentul privind ultima linie din acest cod:

Cod 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 este o clasă Java cu câteva atribute. Serverul creează un ArrayList și îl umple cu variabilele MyVariable ca elemente. Apoi trimite lista completă către client.

Aș dori să știu de ce am un avertisment acolo și cum să codific perfect pentru a avea 0 avertismente. Dacă este posibil, aș dori să evit utilizarea „@SuppressWarnings(„unchecked”)”. 😉

Vă mulțumesc,

Luis

Comentarii

  • Trimiteți o matrice pe socket în loc de o colecție. (MyVariable[]) ois.readObject() este un cast sigur. Pentru a converti o colecție într-un array tipizat, utilizați list.toArray(new MyVariable[0]). Pentru a converti o matrice într-o colecție, utilizați Arrays.asList metoda . –  > Por VGR.
5 răspunsuri
Elliott Frisch

Încercați acest lucru

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.
      }
    }
  }
}

JB Nizet

Este imposibil să evitați acest avertisment. readObject() returnează un obiect. Trebuie să îl distribuiți. Iar turnarea la un tip generic va genera întotdeauna un astfel de avertisment.

Dacă doriți să faceți codul cât mai curat posibil, ceea ce este o idee bună, ar trebui totuși să respectați convențiile de denumire Java și să faceți ca numele variabilelor să înceapă cu o literă minusculă.

Comentarii

  • Sunt destul de sigur că se poate. Răspunsului meu îi lipsește ceva? –  > Por Elliott Frisch.
  • Nu returnează un List<MyVariable>, , și este exagerat. OP ar trebui să știe că a List<MyVariable> este ceea ce se trimite. –  > Por JB Nizet.
minune.șoareci

Nu-mi place asta, dar puteți avea un container (un fel de alias sau tipedef):

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

Și să lucrezi cu MyVariableList în schimb. În acest fel, oferiți în mod explicit suficiente informații compilatorului pentru a face verificarea tipului în timpul execuției.

abhishek

Mă confruntam cu o problemă similară cu OP și am găsit o soluție bună cu o combinație de comentariu de la @VGR și metoda Java 1.8 pentru Array-uri.

Voi oferi răspunsul meu în ceea ce privește întrebarea lui OP, astfel încât să fie generic și să sperăm că îi va ajuta pe alții:

  1. În loc să returnați o colecție (listă), returnați o matrice de la server. Convertiți colecția într-o matrice folosind următoarele în codul de pe server:

    myVariableList.toArray(new MyVariable[0]);

    Dacă performanța este o problemă cu cele de mai sus, se poate folosi următoarea metodă, astfel încât array-ul să nu fie redimensionat:

    myVariableList.toArray(myVariableList.size());

  2. Pe partea de client, se convertește un tablou de obiecte într-un tablou din clasa MyVariable.

    Acest lucru este specific pentru JAVA 8.

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

  3. Apoi, în final, se convertește array-ul într-o colecție (listă).

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

Vă mulțumim.

javaGeek

Am întâlnit și eu o situație similară și am reușit să o rezolv. soluția mea, aplicată la exemplul lui OP este următoarea:

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

Am schimbat convențiile de denumire (așa cum a sugerat cineva, deja) în Java standard (obiectele încep cu caractere minuscule) și am redenumit Clasa MyVariable în Someclass pentru a face explicit faptul că acest lucru se aplică cu adevărat oricărei clase (și nu doar variabilelor). Presupun, de asemenea, că obiectul corespunzător la myList de pe partea serverului de tip ArrayList<Someclass> a fost scris în flux ca un Array Someclass[]. Rețineți că acest lucru este ușor de realizat și este analog cu prima parte a ceea ce abhishek a sugerat deja, dar soluția mea diferă la ultimul pas în măsura în care:

  1. evit să apelez la Arrays.stream
  2. Este mai ușor de citit și rapid perceput ca o simplă (fără logică suplimentară) și checked (care nu generează un avertisment) cast.