Java 对象(反)序列化如何与泛型类一起工作?

问题描述 投票:0回答:1

据我所知,java编译器对泛型类执行类型擦除,以便类型参数的类型信息被Object或其上限替换。序列化和之后的反序列化如何恢复原来的类型?

例如,如果您有一个像这样的通用类:

public class TestGeneric<T extends Serializable> implements Serializable {
    T value;
    public TestGeneric(T value) {
        this.value = value;
    }

    public T getValue() {
        return this.value;
    }
}

我希望 JVM 在运行时看到这个:

public class TestGeneric implements Serializable {
    Serializable value;
    public TestGeneric(Serializable value) {
        this.value = value;
    }

    public Serializable getValue() {
        return this.value;
    }
}

但是如果我执行以下代码,我会得到一个类转换异常:

public static void main(String argv[]) {
        File newFile = new File("./test.txt");
        try {
            if (!newFile.exists()) {
                TestGeneric<Double> testGeneric = new TestGeneric<>(0.2d);

                try (FileOutputStream fos = new FileOutputStream(newFile); ObjectOutputStream oos = new ObjectOutputStream(fos)) {
                    oos.writeObject(testGeneric);
                }
            } else {
                try (FileInputStream fis = new FileInputStream(newFile); ObjectInputStream ois = new ObjectInputStream(fis)) {
                    try {
                        TestGeneric<Boolean> genericRead = (TestGeneric<Boolean>) ois.readObject();
                        Boolean isNotABoolean = genericRead.getValue();
                        System.out.println(isNotABoolean);
                    } catch (ClassNotFoundException e) {
                        System.err.println("Class not found!");
                    }
                }
            }
        } catch(IOException e) {
            System.err.println("IO Exception occurred, reason: " + e.getMessage());
        }
}

对象反序列化后(第二次运行时)出现以下错误:

Exception in thread "main" java.lang.ClassCastException: class java.lang.Double cannot be cast to class java.lang.Boolean (java.lang.Double and java.lang.Boolean are in module java.base of loader 'bootstrap')

看起来即使在执行类型擦除之后,JVM 在运行时也知道该字段的确切类型。这怎么行?

java serialization deserialization type-erasure
1个回答
0
投票
class Abc<T extends Number> { T value; ... }
编译时,

变成

class Abc { Number value; ... }
。这个类的用法如下:

Abc<Integer> abcInst = new Abc<>();
abcInst.value = 123;
int a = abcInst.value;

变成:

Abc abcInst = new Abc();
abcInst.value = Integer.valueOf(123); // visualized boxing
int a = ((Integer) abcInst.value).intValue(); // visualized boxing

当 abcInst 中的

value
不是 Integer 时,此转换失败,因此将生成您得到的异常(类型略有不同)。

您不需要使用序列化来获取此错误消息,滥用泛型并将一种泛型类型转换为另一种泛型类型,然后访问具有错误泛型类型的泛型属性也会导致此错误。

© www.soinside.com 2019 - 2024. All rights reserved.