当前位置: 首页 > 知识库问答 >
问题:

Java8个访问实例字段和方法的lambda不能反序列化

姚正真
2023-03-14

在我看来,这是编译器或JVM中的一个bug,但也许有人有更好的解释。

下面的代码运行正常,但如果我取消注释直接使用“this”的第二个可运行初始化,它将无法反序列化对象(in.readObject()引发异常)。

public class TestClass implements Serializable {
    String               msg = "HEY!";
    SerializableRunnable runnable;
    public TestClass() {
        TestClass self = this;
        runnable = () -> self.say();  // uses a local copy of 'this'
       // runnable = () -> this.say(); // uses 'this' directly
    }
    public void say() {
        System.out.println(msg);
    }
    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        try (ObjectOutputStream out = new ObjectOutputStream(buffer)) {
            out.writeObject(new TestClass());
        }
        try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray()))) {
            TestClass s = (TestClass) in.readObject();
            s.say();
        }
    }
}
interface SerializableRunnable extends Runnable, Serializable {
}

这是根本原因的堆栈跟踪:

java.lang.IllegalArgumentException: Invalid lambda deserialization
    at j8test.TestClass.$deserializeLambda$(TestClass.java:1)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at java.lang.invoke.SerializedLambda.readResolve(SerializedLambda.java:230)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1104)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1810)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1918)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
    at j8test.TestClass.main(TestClass.java:30)

是预期的行为吗?

共有2个答案

叶智
2023-03-14

那是...相当奇怪。

以下是文档中关于序列化lambda的内容:

如果lambda表达式的目标类型及其捕获的参数可序列化,则可以序列化该表达式。然而,与内部类一样,强烈反对lambda表达式的序列化。

我并不完全熟悉捕获的参数,但我假设它指的是lambda捕获的所有元素,这意味着在本例中它指的是这个,所以它是一个捕获的元素。

当进一步探索这条路径时,我们看到TestClass需要可序列化,这似乎是因为它实现了可序列化。此外,它将使用默认的lambda序列化(这通常不是一个好主意),并且它有一个字符串和一个可序列化的可运行的参数,这两个参数都是可序列化的。

因此,在我看来,您在JVM中遇到了一个bug,它可能是由目标等于捕获的参数引起的(this)。

澹台蕴藉
2023-03-14

除了最明显的,我什么都试过了。

这个问题发生在Eclipse中(其中java 8支持仍处于测试阶段),但不是在javac中。因此,一个JDT错误。

[编辑]

我在跑步:

Eclipse IDE for Java and Report Developers
Version: Luna RC1 Release (4.4.0RC1)
Build id: 20140522-1310

Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

OS X 10.9.3

也许在最近的版本中已经纠正了。

 类似资料:
  • 问题内容: 在我看来,这是编译器或JVM中的错误,但也许有人有更好的解释。 以下代码按原样运行正常,但是如果我取消注释第二个初始化(直接使用“ this”),则无法对对象进行反序列化(引发异常)。 这是根本原因的堆栈跟踪: 这是预期的行为吗? 问题答案: 我尝试了所有尝试,但最显而易见的尝试。 该问题发生在Eclipse中(其中Java 8支持仍处于beta中),而在javac中则没有。因此,这是

  • 问题内容: 作为一个小项目,我一直在尝试做一个小事,它可以读取序列化的lambda(从本地或从FTP)并调用它们的运行函数作为测试的一部分,以测试Windows中的文件关联(即打开某些文件类型)使用特定程序打开它们),但不管如何,无论如何,它似乎从未正确地反序列化。 lambda被这样声明 并使用由ObjectOutputStream包装的[n可选] BufferedOutputStream包装的

  • 作为一个小项目,我一直在尝试制作一个小东西来读取序列化的lambda(本地或从FTP)并调用它们的run函数,作为测试的一部分,以在Windows中试验文件关联(即打开某些文件类型会用某个程序打开它们)等等,但无论我尝试什么,它似乎都无法正确地反序列化。 lambda是这样宣布的 并使用由ObjectOutputStream包装的[n可选]BufferedOutputStream包装的FileOu

  • 无法反序列化java实例。lang.String[]值外\u字符串标记[…](通过参考链:[……])。模型用户[“种族”]) 我有一个用户对象的属性。 从这里我可以看出,错误是因为json“type”与属性类型不匹配,但在我的例子中,两者都是字符串数组。 我做错什么了吗? 此外,我无法理解在解析中代表什么。 服务器端正在使用环回,并且ethnicities属性的定义如下: Android客户端使用

  • 我用的是Kotlin,Spring Boot,Jackson数据格式csv。不确定如何将csv的响应作为域对象列表返回。我有以下错误:无法反序列化超出起始\u数组令牌 我的代码如下:

  • 我有一个Spring启动应用程序,我有一个BlogsService调用一个博客库,它应该返回一个与所传递的搜索查询相匹配的博客列表。我得到了以下由第76行引起的结果。有什么想法吗?谢谢 第76行: IllegalArgument异常:不能反序列化的的实例START_ARRAY令牌在[Source: UNKNOWN;行:-1,列:-1]在com.cor.devsquareawsservice.ser