web-dev-qa-db-ja.com

型の安全性:ObjectからArrayList <MyVariable>への未チェックのキャスト

以下は、サーバーからクライアントにArrayListを送信するプログラムの一部です。このコードの最後の行に関する警告を削除したい:

クライアントコード:

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は、いくつかの属性を持つJavaクラスです。サーバーはArrayListを作成し、アイテムとしてMyVariable変数を入力します。その後、完全なリストをクライアントに送信します。

なぜ警告が表示されるのか、警告を0にするために完全にコーディングする方法を知りたいのですが。可能であれば、「@ SuppressWarnings( "unchecked")」の使用を避けたいと思います。 ;)

ありがとうございました、

ルイス

27

これを試して

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

この警告を回避することは不可能です。 readObject()はオブジェクトを返します。あなたはそれをキャストする必要があります。そして、ジェネリック型にキャストすると、常にこのような警告が生成されます。

コードを可能な限りクリーンにしたい場合は(これは良い考えです)、Java命名規則を尊重し、変数名は小文字で開始する必要があります。

13
JB Nizet

私はそれが好きではありませんが、コンテナ(エイリアスまたはtypedefの一種)を持つことができます:

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

代わりにMyVariableListを使用してください。これにより、ランタイムで型チェックを行うのに十分な情報をコンパイラに明示的に提供できます。

2
wonder.mice

私はOPと同様の問題にぶつかり、@ VGRのコメントと配列のJava 1.8メソッドの組み合わせで良い解決策を見つけました。

私はOPの質問の観点から私の答えを提供するので、それは一般的であり、うまくいけば他の人を助ける:

  1. コレクション(リスト)を返す代わりに、サーバーから配列を返します。サーバー側のコードで次を使用して、コレクションを配列に変換します。

    myVariableList.toArray(new MyVariable[0]);

    上記でパフォーマンスが問題になる場合は、以下を使用できます。そのため、配列のサイズを変更する必要はありません。

    myVariableList.toArray(myVariableList.size());

  2. クライアント側で、オブジェクトの配列をMyVariableクラスの配列に変換します。

    これはJava 8。

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

  3. 次に、最後に配列をコレクション(リスト)に変換します。

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

ありがとう。

1
abhishek

私も同様の状況に遭遇し、それを解決することができました。 OPの例に適用される私のソリューションはこれです:

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

私は命名規約を(すでに誰かが提案したように)標準のJava(オブジェクトは小文字で始まる)に変更し、クラスMyVariableの名前を明示的にするためにSomeclassに変更しました。これは実際にはすべてのクラスに適用されます(変数だけでなく)また、タイプArrayList<Someclass>のサーバー側のmyListに対応するオブジェクトは、配列Someclass[]としてストリームに書き込まれていると仮定しています。 abhishekがすでに提案したことの最初の部分に似ていますが、私のソリューションは最後のステップで以下の点で異なります:

  1. Arrays.streamの呼び出しを避けています
  2. 読みやすく、(ロジックを追加せずに)単純なキャストおよびchecked(警告を生成しない)キャストとしてすぐに認識されます。
0
javaGeek