无法从ArrayList <object>转换为ArrayList <myobject>

时间:2016-09-23 15:21:53

标签: java generics casting

我试图创建一个可以从文件中读取序列化对象的通用loadFile方法。但是,对象类型可能会根据要加载的文件而有所不同。我显然误解了铸造是如何工作的,但却无法真正找到我应该在这里做的事情。

以下是我的FileAdapter类:

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

可以看出,我有两种方法从文件加载不同类型的对象,但我想共享实际加载文件的代码。是我试图做到可行但是错误地实施了,或者如果类型不同,这根本不起作用吗?

2 个答案:

答案 0 :(得分: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 :(得分:1)

如果你想确定你的代码不会盲目地进行,除非List实际上包含你期望它包含的内容,将元素类型传递给你的方法,并使用Class.cast来确保每个元素都是你的期待它:

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

如果忽略编译器的“不安全”警告,则可能会在远离实际编码错误的位置发生奇怪的错误,这使得它们很难调试。

执行(ArrayList<Object>) in.readObject()时,如果对象不是ArrayList,您将立即获得ClassCastException,这是一件好事。该异常会阻止您的代码在读取其他内容时使用ArrayList的错误假设继续进行。

但泛型类型,无论是<Object>还是<Fund>还是其他任何类型,都是由于类型擦除而在运行时不存在的信息。因此,无论ArrayList包含什么,不安全的通用转换都不会抛出任何异常。只有在稍后,当您尝试从ArrayList读取元素时,才会发生ClassCastException。