什么意思:可序列化的类没有声明静态最终serialVersionUID字段?

248

我收到了标题中给出的警告信息,希望能够理解并解决它。我已经在这个问题上找到了一些答案,但由于技术术语过多而无法理解这些答案。有可能用简单的话来解释这个问题吗?

P.S. 我知道什么是面向对象编程(OOP)。我知道什么是对象、类、方法、字段和实例化。

P.P.S. 如果有人需要我的代码,它在这里:

import java.awt.*;
import javax.swing.*;


public class HelloWorldSwing extends JFrame {

        JTextArea m_resultArea = new JTextArea(6, 30);

        //====================================================== constructor
        public HelloWorldSwing() {
            //... Set initial text, scrolling, and border.
            m_resultArea.setText("Enter more text to see scrollbars");
            JScrollPane scrollingArea = new JScrollPane(m_resultArea);
            scrollingArea.setBorder(BorderFactory.createEmptyBorder(10,5,10,5));

            // Get the content pane, set layout, add to center
            Container content = this.getContentPane();
            content.setLayout(new BorderLayout());
            content.add(scrollingArea, BorderLayout.CENTER);
            this.pack();
        }

        public static void createAndViewJFrame() {
            JFrame win = new HelloWorldSwing();
            win.setTitle("TextAreaDemo");
            win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            win.setVisible(true);
        }

        //============================================================= main
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable(){
                public void run(){
                    createAndViewJFrame();
                }
            });
        }

}

讨论中的警告信息是否可能是导致我的GUI应用程序冻结的原因? - Roman
不,这与你的GUI冻结无关。 - james
2
Dup: https://dev59.com/Y3VC5IYBdhLWcg3wdw65 - skaffman
5个回答

170

javadoc中可以得知:

序列化运行时为每个可序列化的类关联一个版本号,称为serialVersionUID,在反序列化期间用于验证序列化对象的发送方和接收方是否已加载了与序列化兼容的该对象的类。如果接收方加载了具有不同serialVersionUID的对象类,那么反序列化将导致InvalidClassException。可序列化的类可以通过声明一个名为"serialVersionUID"的字段来显式地声明自己的serialVersionUID,该字段必须是静态、最终和长整型类型:

您可以配置您的IDE:

  • 忽略此警告而不是给出警告。
  • 自动生成一个ID。

至于你的附加问题“讨论的警告消息是否是我的GUI应用程序冻结的原因?”:

不可能,它只会在序列化对象并在类已更改的不同位置(或时间)进行反序列化时发生问题,这不会导致冻结,而是导致InvalidClassException


13
您也可以让您的IDE自动生成一个。 - BalusC
4
@BalusC - 我们如何在eclipse中实现这一点?自动生成安全吗? - Jedi Knight
4
在Eclipse中,依次点击“Window>Preferences>Java>Code Style>Clean Up>Missing Code”,在“Potential programming problems”下启用“Add serial version ID”。如果你使用的是默认配置文件,则需要将其保存为其他配置文件。 - 0x41414141
5
如果你不使用序列化,请勿自动生成serialVersionUID。这已经在编译过程中发生了,不需要在源代码中添加愚蠢的随机数来使你的 IDE 满意。只需关闭 Eclipse 的警告即可,因为实际的混淆来自于此。如果您确实想要使用序列化(现在很可能性接近于 0),则应该学习一下关于它的知识,并将 serialVersionUID 用作版本号(从 1 开始,并使用特殊代码读取旧版本时增加)。 - john16384

46
迄今为止,其他回答中已经有很多技术信息。如您所请求,我将尝试用简单的语言回答。
如果您想将对象实例转储到原始缓冲区、保存到磁盘、在二进制流中传输(例如,在网络套接字上发送对象),或以其他方式创建对象的序列化二进制表示,则需要对其进行序列化。(有关序列化的更多信息,请参见维基百科上的Java序列化)。
如果您不打算序列化类,则可以在类上方添加注解@SuppressWarnings("serial")
如果您要进行序列化,那么您需要担心许多事情,所有这些事情都集中在正确使用UUID上。基本上,UUID是一种将要序列化的对象“版本化”的方法,以便任何正在反序列化的过程都知道它正在正确地反序列化。我建议阅读确保序列化对象的正确版本控制 获取更多信息。

你的引用中有几个重大错误,还存在一些自相矛盾之处。 - user207421
15
若您列举出错误,对所有人都会很有帮助。 - MrMas
@EJP刚才我突然意识到我的答案中有两个引用。你是指哪一个引用? - MrMas
1
我指的是Javaworld文章,但你回答中唯一的引用是第三方资源,这些资源没有比本网站上的答案更有权威性:通常情况下甚至不如本网站上的答案。唯一相关的引用是规范参考文献:JLS、JVM规范、Java对象序列化规范和Javadoc。 - user207421

37

警告的原因可以在这里找到详细文档,解决方案是关闭警告或者在代码中加入以下声明来提供版本UID。实际值并不重要,如果愿意,可以从999开始,但是当您对类进行不兼容的更改时,请更改它。

public class HelloWorldSwing extends JFrame {

        JTextArea m_resultArea = new JTextArea(6, 30);
        private static final long serialVersionUID = 1L;

2
警告的原因在Java对象序列化规范和Javadoc中有记录。StackOverflow的答案不是规范性参考。 - user207421

27
每当发生影响序列化的更改(例如添加字段、删除字段、更改字段顺序等)时,必须进行更改。这是不正确的观点,您将无法引用权威来源支持此主张。按照Object Serialization SpecificationVersioning of Serializable Objects部分给定的规则,在发生不兼容更改时(不包括添加字段或更改字段顺序),并且当您没有提供能够处理更改的readObject(),writeObject(),readResolve()和/或writeReplace()方法以及serializableFields声明时,应进行更改。

5
任何可序列化的类(即实现了Serializable接口的类)都应该声明这个UID,并且每当影响序列化的任何内容发生更改时,它必须被更改。这些更改包括增加字段、删除字段、改变字段顺序等。在反序列化期间会检查此字段的值,如果序列化对象的值与当前虚拟机中的类的值不相等,则会抛出异常。
请注意,尽管此值为静态值,但由于上述原因,它将与对象一起序列化。

2
我可以将一个可序列化的类封装在JFrame中吗?UID是什么,我如何声明它?我的代码是否“更改了影响序列化的内容”?实际上,序列化是什么意思? - Roman
是的,JFrame是一个实现Serializable接口的java.awt.Component。代码从不更改影响序列化的任何内容,只有程序员才会这样做。我不知道有没有列出所有影响序列化的更改的列表。请查看http://en.wikipedia.org/wiki/Serialization#Java,了解Java中序列化的描述。 - Thomas Lötzer
2
它没有与对象序列化。除非您想要破坏兼容性,或者已经通过偏离规范版本控制部分中所述的内容来这样做,否则不应更改它。这不包括添加或重新排序字段。正确的参考资料不是维基百科,而是对象序列化规范。 - user207421
无论是额外的字段、删除的字段还是字段顺序的更改,只有当您没有实现readObject()来处理更改时,类型更改才会起作用。 - The incredible Jan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接