lambda的序列化和反序列化

Can*_*cer 15 java java-8

以下代码抛出

Exception in thread "main" java.lang.ClassCastException: test.Subclass2 cannot be cast to test.Subclass1
at test.LambdaTest.main(LambdaTest.java:17)
Run Code Online (Sandbox Code Playgroud)
public class LambdaTest {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ToLongFunction<B> fn1 = serde((ToLongFunction<B> & Serializable) B::value);
        ToLongFunction<C> fn2 = serde((ToLongFunction<C> & Serializable) C::value);
        fn1.applyAsLong(new B());
        fn2.applyAsLong(new C()); // Line 17 -- exception here!
    }

    private static <T extends Serializable> T serde(T t) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        new ObjectOutputStream(bos).writeObject(t);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos
                .toByteArray()));
        return (T) ois.readObject();
    }
}

class A {
    public long value() {
        return 0;
    }
}

class B extends A { }

class C extends A { }
Run Code Online (Sandbox Code Playgroud)

原因似乎是在序列化和反序列化之后,fn1和fn2都以同一个类结束.这是一个JDK /编译器错误还是我错过了关于lambdas的序列化和反序列化的一些内容?

Mar*_*nik 9

看看2016年提出的Open JDK问题:

lambda的反序列化导致ClassCastException

它非常精确地匹配您的场景:

  • 两个(不同的)类,B并且C都扩展了相同的基类A,它有一个方法,String f().
  • 为类型对象创建Supplier方法的引用; 叫这个[ ].f()Bbfnew B()::f
  • 为类型对象创建Supplier方法的引用; cal this [ ].f()Ccfnew C()::f
  • 序列化cf(ObjectOutputStream#writeObject)
  • 当序列化cf被反序列化(ObjectInputStream#readObject)时,ClassCastException抛出一个说C不能将类强制转换为类B

关于这个问题有一个有趣的讨论,但丹史密斯最后的评论似乎指出:

对此特定测试用例的重要观察:方法引用的"限定类型"(即字节码命名的类)应与调用的限定类型相同:接收器的类型.javac使用声明类的类型是错误的.见JDK-8059632.

修复该错误,我认为不同捕获类型的问题消失了.