序列化和不可变对象

发布于 2024-08-09 15:42:41 字数 150 浏览 6 评论 0原文

我有一个用于不可变使用的类,因此我想将所有字段标记为final

然而,该类被序列化和反序列化以通过网络发送。为此,需要一个空的构造函数。这阻止我创建最终字段。

我确信这是一个相当常见的问题,但我找不到解决方案。我应该如何进行?

I have a class which is intended for immutable use, hence I would like to label all the fields final.

However the class is serialized and deserialized to send over the network. For this to work an empty constructor is required. This prevents me creating the final fields.

I'm sure this is a fairly common problem but I can't find a solution. How should I proceed?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

天气好吗我好吗 2024-08-16 15:42:41

不需要无参数构造函数。最派生的不可序列化类确实需要一个可供最不派生的可序列化类使用的无参数构造函数。

如果您需要更改 readObject 内的字段,请通过 readResolvewriteReplace 使用串行代理。

A no-arg constructor is not required. The most derived non-serialisable class does need a no-arg constructor available to the least-most derived serialisable class.

If you need to mutate fields inside a readObject, then use a serial proxy through readResolve and writeReplace.

︶ ̄淡然 2024-08-16 15:42:41

在典型的序列化情况下,类不需要具有空构造函数或可序列化的非最终字段。

现在,如果您必须执行自己的序列化,或者您需要子类化未实现可序列化的类,那就是另一回事了。

因此,您需要提供更多有关您遇到问题的详细信息。

In the typical serialization case, it is not required that class have an empty constructor or non-final fields to be serializable.

Now, if you have to do your own serialization, or you need to subclass a class that doesn't implement Serializable, that is a different story.

So you need to provide some more details of how you are having a problem.

此问题是 Java 语言的未解决错误。 (请注意,这只适用于必须手动执行序列化的情况,例如使用 readObject)

This issue is an open bug on the Java language. (Note that this only applies if you have to do the serialization manually, such as with readObject)

浅紫色的梦幻 2024-08-16 15:42:41

与前面所说的相呼应,如果您采用实现 java.io.Serialized 接口的方法,则不需要无参数构造函数。例如,看一下 java.lang.Integer 源代码,一个简单的可序列化/不可变类,它有两个构造函数:一个接受 int,另一个接受 String。源代码: http://www.docjar.com/html /api/java/lang/Integer.java.html。 Javadoc: http://java.sun.com/ javase/6/docs/api/java/lang/Integer.html

另外,根据类的复杂性和您正在执行的操作,您可以考虑通过 java.io.Externalizable 接口实现序列化(尽管有些人认为它已经过时,并且它确实需要无参数构造函数)。以下是 SO 的概述: Serialized 和 Serialized 有什么区别和 Java 中的可外部化?,这是官方 Java 教程:http://java.sun.com/docs/books/tutorial/javabeans/persistence/index.html

To echo what has been said, no-arg constructors are not a requirement if you are taking the route of implementing the java.io.Serializable interface. Take a look at the java.lang.Integer source code for example, a simple serializable/immutable class that has two constructors: one that takes an int, and one that takes a String. Source code: http://www.docjar.com/html/api/java/lang/Integer.java.html. Javadoc: http://java.sun.com/javase/6/docs/api/java/lang/Integer.html.

Also depending on the complexity of your class and what you are doing, you could consider implementing serialization via the java.io.Externalizable interface (although some consider it outdated, and it DOES require a no-arg constructor). Here's an overview on SO: What is the difference between Serializable and Externalizable in Java?, and here's the official Java tutorial: http://java.sun.com/docs/books/tutorial/javabeans/persistence/index.html.

回眸一笑 2024-08-16 15:42:41

作为记录,因为我有类似的问题:
我收到一条消息“java.io.InvalidClassException:com.example.stuff.FooBar; com.example.stuff.FooBar;没有有效的构造函数

我认为这是因为它缺少默认构造函数。但上面的答案证实它不是强制性的(但是我们的应用程序使用了一个旧的序列化器,它确实需要一个默认的构造函数,因此可能会出现这种情况)。

然后我找到了一个页面,上面写着:

如果为继承而设计的类不可序列化,则它
可能不可能编写可序列化的子类。具体来说,它
如果超类不提供可访问的,则这是不可能的
无参数构造函数。

我想这就是我收到的消息。看起来核心问题是经典的:我将一个类声明为可序列化,但超类不是!我将可序列化接口在层次结构中向上移动,一切都很好。

但这个消息有点误导......:-)

For the record, since I had a similar issue:
I had a message "java.io.InvalidClassException: com.example.stuff.FooBar; com.example.stuff.FooBar; no valid constructor"

I thought it was because it was lacking a default constructor. But the above answers confirm it is not mandatory (but our app. uses an old serializer that indeed require a default constructor, so the case can arise).

Then I found a page stating:

If a class that is designed for inheritance is not serializable, it
may be impossible to write a serializable subclass. Specifically, it
will be impossible if the superclass does not provide an accessible
parameterless constructor.

Hence the message I got, I suppose. It appeared that the core issue was classical: I declared a class as serializable, but the superclass was not! I moved the Serializable interface up in the hierarchy, and all was well.

But the message was a bit misleading... :-)

停滞 2024-08-16 15:42:41

不需要无参数构造函数。让我们阅读源代码:

// java.io.ObjectStreamClass
private static Constructor<?> getSerializableConstructor(Class<?> cl) {
    Class<?> initCl = cl;
    while (Serializable.class.isAssignableFrom(initCl)) {
        if ((initCl = initCl.getSuperclass()) == null) {
            return null;
        }
    }
    ...
}

因此,实际上类型层次结构中最近的非 Serialized 类中需要无参数构造函数。

这意味着下面的类Domain可以被序列化。

class Domain implements Serializable {
    private final int a;

    public Domain(int a) {
      this.a = a;
    }
}

Son 类不能:

class Father{
  private final int a;

  public Father(int a) {
    this.a = a;
  }
}

class Son extends Father implements Serializable {
  public Son(int a) {
    super(a);
  }
}

A no-arg constructor is not required. Let's read the source code:

// java.io.ObjectStreamClass
private static Constructor<?> getSerializableConstructor(Class<?> cl) {
    Class<?> initCl = cl;
    while (Serializable.class.isAssignableFrom(initCl)) {
        if ((initCl = initCl.getSuperclass()) == null) {
            return null;
        }
    }
    ...
}

So, actually the no-arg constructor is required in the nearest not Serializable class in the type hierarchy.

It means the following class Domain can be serialized.

class Domain implements Serializable {
    private final int a;

    public Domain(int a) {
      this.a = a;
    }
}

But the class Son can't:

class Father{
  private final int a;

  public Father(int a) {
    this.a = a;
  }
}

class Son extends Father implements Serializable {
  public Son(int a) {
    super(a);
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文