0

次のコードがあるとします。

Object li = new Object(); 

// this causes a compiler warning   

ArrayList<String> lo = (ArrayList<String>)(li); 

わかりました、質問を編集しました。申し訳ありませんが、間違いを犯しました。要点は、ターゲットがパラメーター化された型であるターゲットにキャストすると、コンパイル時に警告が発生するため、より良い解決策はありますか?コードがコンパイル時の警告を引き起こさないようにしますか?

配列を扱う場合、キャストの使用を置き換える Arrays.newInstance があります。


元の質問のコード:

// List<String> is a superclass of ArrayList

List<String>      listOne =  new List<String>();

ArrayList<String> listTwo = (List<String>) listOne; 
4

2 に答える 2

1

List は interfaceであるため、List をインスタンス化することはできません。

ArrayListは、Listインターフェイス実装するクラスです。

あなたはこれを行うことができます:

List<String> listOne  =  new ArrayList<String>();
List<String> listTwo  =  listOne;

listOneを使用するコードがリストの種類を気にしない場合、これは正しいアプローチです。

これが良いアプローチである理由を示す例を次に示します。

List<String> someList = createList();

ここで、 someListはcreateListという名前のメソッドの戻り値に設定されます。この状況では、 someListがどのようなリストなのかわかりません。ArrayList、Vector、Stack などの可能性があります。createListが List インターフェイスを実装するオブジェクトを返す限り、上記のコードは機能します。このアプローチにより、createListのコードは、それを呼び出すコードに影響を与えることなく変更できます。

これを行うこともできます:

ArrayList<String> listOne  =  new ArrayList<String>();
ArrayList<String> listTwo  =  listOne;

これは柔軟ではありませんが、リストを具体的に ArrayLists として扱うことができます。

技術的には、これを行うことができますが、それは良い考えではありません:

List<String>      listOne  =  new ArrayList<String>();
ArrayList<String> listTwo  =  (ArrayList<String>) listOne;

List を宣言し、ArrayList をインスタンス化することによって、インターフェイスにプログラムする方が適切です。

インターフェイスへのプログラミングの利点を示す例を次に示します。

public static void testIt() {

    List someList;
    ArrayList anArrayList;

    /*
     *  all of these will work 
     */

    someList = createVectorAsList();
    printList(someList);

    someList = createStackAsList();
    printList(someList);

    someList = createArrayListAsList();
    printList(someList);

    // you CAN assign an ArrayList to a List

    someList = createArrayList();
    printList(someList);

    // you CAN treat an ArrayList as a List

    anArrayList = createArrayList();
    printList(anArrayList);


    /* 
     *  none of these work 
     */

    // you can NOT assign List to an ArrayList

    anArrayList = createStackAsList();
    anArrayList = createVectorAsList();

    // you can NOT pass anything but an ArrayList to printArrayList

    printArrayList(createStackAsList());
    printArrayList(createVectorAsList());
    printArrayList(createArrayListAsList());

}

/** Prints any List */

public void printList(List someList) {
    for (Object o : someList) {
        System.out.println(o.toString());
    }
}

/** Prints ArrayLists only */

public void printArrayList(ArrayList someList) {
    for (Object o : someList) {
        System.out.println(o.toString());
    }
}

public List createVectorAsList() {
    Vector v = new Vector();
    v.add("I am a vector element");
    return v;
}

public List createStackAsList() {
    Stack s = new Stack();
    s.add("I am a stack element");
    return s;
}

public List createArrayListAsList() {
    ArrayList ar = new ArrayList();
    ar.add("I am an array list element");
    return ar;
}

public ArrayList createArrayList() {
    ArrayList ar = new ArrayList();
    ar.add("My array is not returned as a list...");
    return ar;
}
于 2012-08-31T03:01:23.893 に答える
1

このような状況にある場合、選択肢は 2 つあります。1 つ目は、未チェックのキャストを行うことです。

Object o = getObjectFromSomewhereMysterious();
List<String> lst = (List<String>)o; //compiler warning

これにより、あなたが言及した警告が発生します。つまり、型が eraseoであるため、実行時にキャストは aであることを確認することしかできず、 aListではないことを意味しますList<String>。たとえば、oが aHashMapの場合、キャストはすぐに失敗しますが、 a の場合は失敗しません...後で a のようなList<Integer>要素を処理しようとするときまで。これは「ヒープの汚染」として知られています:lstString

//some later place in the code path - who knows, it could be miles away
String str = lst.get(0); //ClassCastException if lst isn't really a List<String>

キャストが安全であることを確認できる限り、コンパイラの警告を抑制することができます。

@SuppressWarnings("unchecked") //this is safe because blah blah blah
List<String> lst = (List<String>)o;

警告を抑制できる理由を常に文書化してください。これは、コードを保守しやすくするのに役立ちます。

2 番目のオプションは、安全にプレイすることです。

List<?> lst = (List<?>)o;

これlstは、List不明なタイプであることを意味します。これにより、チェックされていないキャストを回避できますが、でできることには制限が課されますlst

lst.add("some string"); //compiler error

lstが sを保持できるかどうかがわからないため、このステートメントは違法Stringです。私たちができる最善のことはそれから読み取ることですが、それでも要素は次のように型付けされるだけObjectです:

Object element = lst.get(0);
于 2012-08-31T06:18:48.060 に答える