2016-09-23 29 views
2

ファイルからシリアル化されたオブジェクトを読み取ることができる一般的なloadFileメソッドを作成しようとしています。ただし、オブジェクトの種類はロードするファイルによって異なる場合があります。私は明らかにキャスティングの仕組みを誤解していましたが、私がここでやるべきことを本当に見つけることができません。ArrayList <Object>をArrayListにキャストできません<MyObject>

見ることができるように
public class FileAdapter { 

    public ArrayList<Transaction> loadTransactions() { 

     return (ArrayList<Transaction>) loadFile(new File("data/transactions.ser")); 
    } 

    public ArrayList<Fund> loadFunds() { 

     return (ArrayList<Fund>) loadFile(new File("data/funds.ser")); 
    } 

    private ArrayList<Object> loadFile(File file) { 

     ArrayList<Object> obj = new ArrayList<>(); 

     FileInputStream fis = new FileInputStream(file); 
     in = new ObjectInputStream(fis); 
     obj = (ArrayList<Object>) in.readObject(); 

     return obj; 
    } 
} 

、私はファイルからさまざまな種類のオブジェクトをロードする二つの方法がありますが、私は実際にファイルをロードするコードを共有したい:

以下は私のFileAdapterクラスです。私がしようとしていることは実現可能ですが、間違って実装されているのですか?

+1

'loadFile()'は 'in.readObject()'からオブジェクトを返すこともできます。そして、呼び出し元がそれをキャストする対象を決定させることができます。 – nickb

+1

またはいくつかのジェネリック(つまり、ArrayList loadFile) –

+2

そのようなものが必要なら、 'private T ArrayList loadFile(File file)'のようなジェネリックを使うべきです。 –

答えて

4

それは次のように、あなたの方法loadFileの定義にbounded type parameterを定義することによって行うことができる:一覧が実際に何を期待含まれていない限り、あなたはあなたのコードが盲目的に進まない一定にしたい場合は

public ArrayList<Transaction> loadTransactions(){ 
    return loadFile(new File("data/transactions.ser")); 
} 

public ArrayList<Fund> loadFunds(){ 
    return loadFile(new File("data/funds.ser")); 
} 

private <T> ArrayList<T> loadFile(File file) { 
    ArrayList<T> obj = new ArrayList<>(); 
    ... 
    return (ArrayList<T>) in.readObject(); 
} 
1

public ArrayList<Transaction> loadTransactions() { 
    return loadFile(new File("data/transactions.ser"), Transaction.class); 
} 

public ArrayList<Fund> loadFunds() { 
    return loadFile(new File("data/funds.ser"), Fund.class); 
} 

private <T> ArrayList<T> loadFile(File file, 
            Class<T> elementType) { 
    ArrayList<?> obj; 

    try (FileInputStream fis = new FileInputStream(file); 
     ObjectInputStream in = new ObjectInputStream(fis)) { 

     // This is safe, because it does not make any assumptions 
     // about the ArrayList's generic type. 
     obj = (ArrayList<?>) in.readObject(); 
    } catch (IOException | ClassNotFoundException e) { 
     throw new RuntimeException(e); 
    } 

    ArrayList<T> typedList = new ArrayList<>(obj.size()); 
    for (Object element : obj) { 
     typedList.add(elementType.cast(element)); 
    } 

    return typedList; 
} 

あなたはコンパイラの「安全でない」の警告を無視した場合、あなたはstrのリスク:、含まれているあなたの方法に要素の型を渡し、すべての要素が、あなたはそれがあることを期待するものであることを確認するためにClass.castを使用すること実際のコーディングエラーが発生していた場所から遠く離れた場所でエラーが発生するため、デバッグが非常に困難になります。

(ArrayList<Object>) in.readObject()を実行すると、オブジェクトがArrayListでない場合、すぐにClassCastExceptionが発生します。これは良いことです。例外は、何か他のものが読み込まれたときにArrayListを持っているという間違った前提でコードが進まないようにします。

しかし、<Object>または<Fund>などの汎用タイプは、タイプ消去のため実行時に存在しない情報です。そのため、安全でないジェネリックキャストは、ArrayListに含まれるものに関係なく、例外をスローしません。後で、ArrayListから要素を読み取ろうとすると、ClassCastExceptionが発生します。

関連する問題