当前位置:  开发笔记 > 编程语言 > 正文

什么是serialVersionUID,我为什么要使用它?

如何解决《什么是serialVersionUID,我为什么要使用它?》经验,为你挑选了21个好方法。

serialVersionUID缺少时,Eclipse会发出警告.

可序列化类Foo不声明long类型的静态最终serialVersionUID字段

serialVersionUID它是什么以及为什么重要?请显示缺失serialVersionUID会导致问题的示例.



1> Jon Skeet..:

这些文档java.io.Serializable可能与您获得的解释一样好:

与每个序列化类版本号序列化运行时相关联,称为serialVersionUID,其被反序列化过程用于验证序列化对象的发送者和接收者都加载的类该对象是相对于序列兼容.如果接收者已经为对象加载了一个类,该类serialVersionUID与对应的发送者类的对象不同,那么反序列化将导致一个 InvalidClassException.可序列化类可以serialVersionUID通过声明名为serialVersionUID必须为static,final和type 的字段来显式声明自己的类long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

如果可序列化类未显式声明a serialVersionUID,则序列化运行时将serialVersionUID基于类的各个方面计算该类的默认值,如Java(TM)对象序列化规范中所述.但是,强烈建议所有可序列化类显式声明serialVersionUID值,因为默认serialVersionUID计算对类详细信息高度敏感,可能因编译器实现而异,因此InvalidClassExceptions在反序列化期间可能会导致意外.因此,为了保证serialVersionUID跨不同java编译器实现的一致值,可序列化类必须声明一个显式serialVersionUID值.强烈建议明确serialVersionUID声明尽可能使用private修饰符,因为此类声明仅适用于立即声明的类serialVersionUID字段作为继承成员无用.


原因在于第二段:如果您没有明确指定serialVersionUID,则会自动生成一个值 - 但这很脆弱,因为它依赖于编译器实现.
所以,你所说的基本上是,如果用户不理解上述所有材料,那么用户不必担心序列化?我相信你回答了"怎么样?" 而不是解释"为什么?".我,其中一个,不明白我为什么要烦扰SerializableVersionUID.
@JohnMerlino:我不希望它说你需要*一个 - 但它可能*建议*一个,以帮助你正确序列化异常.如果你不打算序列化它们,你真的不需要常数.
@JohnMerlino,回答你为什么部分问题:异常实现[Serializable](http://docs.oracle.com/javase/7/docs/api/java/lang/Exception.html)和eclipse警告你有没有设置serialVersionUID,这是一个好主意(如果你不想序列化类),以避免JonSkeet的帖子概述的问题.
为什么Eclipse说我需要"private static final long serialVersionUID = 1L;" 当我扩展Exception类?
@smwikipedia:要反序列化数据?是.虽然反序列化你没有源的类的数据会很奇怪.二进制序列化不应该(IMO)用作通用公共协议.
@Ziggy我认为应该有正确的词.
@ user1050755:所以你很高兴改变你的编译器,即使它不会改变字段本身的任何细节,也会使任何存储的数据都不可读?或者添加一个公共静态方法,它真的不应该改变序列化细节?之前被这种事情所困扰,这是一个非常明确的"骗局".现在可能是因为如果算法设计得更好,那就没关系 - 但是按照设计的方式来说,这是个坏消息.
@ user1050755:基本上每种方式都有利弊.
@bpoiss:然后它将尝试使用新类对旧数据进行反序列化,并且将导致错误或有效破坏数据,具体取决于确切的更改。
@Ziggy如果"..因为默认的serialVersionUID计算对类细节高度敏感,可能因编译器实现而异,因此在反序列化期间可能会导致意外的InvalidClassExceptions." 不回答为什么然后我害怕,我将要求你定义为什么:D
@proudandhonour:是的,你应该这样做.
仅花费我的两分钱,这就是Spark和其他并行化API中的一个问题,这些API依赖于跨集群对Java类进行序列化。
提示:如果您忘记添加`serialVersionUIDfield`,并且希望更改类而不影响它,您可以检查它在未修改时的值是什么,并在修改它之后在此类上设置它,使用此call(发现自:stackoverflow.com/a/26822688/878126):`long serialVersionUID = ObjectStreamClass.lookup(YourClass.class).getSerialVersionUID();`

2> MetroidFan20..:

如果你的序列化只是因为你必须为了实现而序列化(谁在乎你是否为序列化HTTPSession,例如......如果它存储与否,你可能不关心de-serializing表单对象),那么你可以忽略这个.

如果您实际使用的是序列化,那么只有您计划直接使用序列化存储和检索对象才有意义.该serialVersionUID代表你的类版本,你应该增加,如果你的类的当前版本不向后与以前的版本兼容.

大多数情况下,您可能不会直接使用序列化.如果是这种情况,SerialVersionUID请单击快速修复选项生成默认值,不要担心.


我要说如果你没有使用序列化进行永久存储,你应该使用@SuppressWarnings而不是添加值.它减少了类的混乱,它保留了serialVersionUID机制的能力,以保护您免受不兼容的更改.
@MewididFan2002:我认为@ TomAnderson的"serialVersionUID"保护您免受不兼容的更改是有效的.如果您不希望将类用于永久存储,则使用`@ SuppressWarnings`可以更好地记录目标.
我没有看到如何添加一行(@SuppressWarnings注释)而不是另一行(可序列化的id)"使类减少".如果您没有使用序列化进行永久存储,为什么不使用"1"呢?在这种情况下,你不会关心自动生成的ID.
"如果您的类的当前版本与其先前版本不向后兼容,则应该增加它:"您应该首先探索序列化的广泛对象版本控制支持,(a)以确保该类现在实际上是序列化不兼容的方式,根据规范很难实现; (b)尝试一个方案,如自定义read/writeObject()方法,readResolve/writeReplace()方法,serializableFields声明等,以确保流保持兼容.改变实际的`serialVersionUID`是最后的手段,是绝望的忠告.
当类的初始作者明确介绍时,@ IQJ的serialVersionUID增量会出现.我会说,jvm生成的序列号,应该没问题.这是我在序列化中看到的最好[答案](http://stackoverflow.com/a/27601774/3317808).

3> Scott Bale..:

我不能错过这个机会来插入Josh Bloch的书Effective Java(第2版).第11章是Java序列化不可或缺的资源.

根据Josh,自动生成的UID是基于类名,实现的接口以及所有公共和受保护成员生成的.以任何方式改变任何这些将改变serialVersionUID.因此,只有当您确定不会将一个以上版本的类序列化时(无论是跨进程还是稍后从存储中检索),您都不需要弄乱它们.

如果你忽略他们,现在,和以后查找您需要更改类以某种方式,但保持兼容性瓦特/旧版本的类,你可以使用JDK工具的serialver生成serialVersionUID类,并明确设置在新课上.(根据您的更改,您可能还需要通过添加writeObjectreadObject方法来实现自定义序列化- 请参阅Serializablejavadoc或上述第11章.)


因此,如果有人担心类的旧版本的兼容性,那么人们可能会厌烦使用SerializableVersionUID?
值得注意的是,Joshua Bloch建议,对于*every*Serializable类,值得指定串行版本uid.引自第11章:_无论你选择什么序列化形式,在你编写的每个可序列化类中声明一个显式的串行版本UID.这消除了串行版本UID作为不兼容的潜在来源(第74项).还有一个小的性能优势.如果没有提供串行版本UID,则需要在运行时生成一个昂贵的计算._
是的,如果较新的版本将任何公共成员更改为受保护,则默认的SerializableVersionUID将不同并将引发InvalidClassExceptions.
class Name,实现的接口,所有公共和受保护的方法,所有实例变量.

4> matt b..:

您可以告诉Eclipse忽略这些serialVersionUID警告:

窗口>首选项> Java>编译器>错误/警告>潜在的编程问题

如果你不知道,你可以在本节中启用许多其他警告(甚至有一些报告为错误),许多非常有用:

潜在的编程问题:可能的意外布尔赋值

潜在的编程问题:空指针访问

不必要的代码:永远不会读取局部变量

不必要的代码:冗余空值检查

不必要的代码:不必要的演员或'instanceof'

还有很多.


upvote但只是因为原始海报似乎没有序列化任何东西.如果海报说"我正在序列化这个东西......"那么你就会得到一个投票:P
@Gardner - >同意了!但提问者也想知道为什么他可能不想被警告.
提问者显然关心为什么应该有UID.因此,简单地告诉他忽略警告应该被低估.
是的 - 我假设提问者根本不想被警告

5> Alexander To..:

serialVersionUID促进序列化数据的版本控制.序列化时,其值与数据一起存储.反序列化时,将检查相同的版本以查看序列化数据如何与当前代码匹配.

如果要对数据进行版本控制,通常从serialVersionUID0 开始,并将其与类的每个结构更改一起使用,这会改变序列化数据(添加或删除非瞬态字段).

内置的反序列化机制(in.defaultReadObject())将拒绝从旧版本的数据反序列化.但是如果你愿意,你可以定义自己的readObject()函数,它可以读回旧数据.然后,此自定义代码可以检查serialVersionUID以便知道数据所在的版本并决定如何对其进行反序列化.如果您存储的代码化数据能够存储多个版本的代码,则此版本控制技术非常有用.

但是,在如此长的时间内存储序列化数据并不常见.使用序列化机制临时将数据写入例如高速缓存或通过网络将其发送到具有相同版本的代码库相关部分的另一程序更为常见.

在这种情况下,您对维护向后兼容性不感兴趣.您只关心确保通信的代码库确实具有相同类型的相关类.为了便于进行此类检查,您必须serialVersionUID像以前一样维护,并且在更改类时不要忘记更新它.

如果您忘记更新该字段,最终可能会得到两个不同版本的类,这些类具有不同的结构但具有相同的结构serialVersionUID.如果发生这种情况,默认机制(in.defaultReadObject())将不会检测到任何差异,并尝试反序列化不兼容的数据.现在,您最终可能会遇到神秘的运行时错误或静默失败(空字段).这些类型的错误可能很难找到.

因此,为了帮助这个用例,Java平台为您提供了不serialVersionUID手动设置的选择.相反,类结构的哈希将在编译时生成并用作id.这种机制将确保您永远不会有具有相同ID的不同类结构,因此您将无法获得上面提到的这些难以跟踪的运行时序列化失败.

但是自动生成的id策略有一个缺点.也就是说,同一类的生成的id可能在编译器之间有所不同(如上面的Jon Skeet所述).因此,如果您在使用不同编译器编译的代码之间传递序列化数据,则建议手动维护ID.

如果你向后兼容你的数据,就像你提到的第一个用例一样,你也可能想要自己维护id.这是为了获得可读的ID并且可以更好地控制它们何时以及如何变化.


添加或删除非瞬态字段不会使类序列化不兼容.因此没有理由在这些变化上"碰撞".
@EJP:嗯?添加数据肯定会改变我的世界中的序列化数据.
我的观点正是我所说的.添加或删除非瞬态字段不会使类序列化不兼容.因此,每次执行此操作时都不需要碰撞serialVersionUID.
@AlexanderTorstling阅读我写的内容.我没有说它没有'改变序列化数据'.我说'它不会使类序列化 - 不兼容'.这不是一回事.您需要阅读对象序列化规范的版本控制章节.
@EJP:我意识到添加一个非瞬态字段并不一定意味着你使类序列化不兼容,但它是一个改变序列化数据的结构变化,你通常想要在这样做时碰撞版本,除非你处理向后兼容性,我也在后面的帖子中解释过.你的观点到底是什么?

6> Thalaivar..:

什么是serialVersionUID,我为什么要使用它?

SerialVersionUID是每个类的唯一标识符,JVM用于比较类的版本,确保在反序列化期间加载序列化期间使用相同的类.

指定一个可以提供更多控制,但如果您未指定,JVM会生成一个控件.生成的值可能因不同编译器而异.此外,有时您只是出于某种原因禁止对旧的序列化对象[ backward incompatibility]进行反序列化,在这种情况下,您只需更改serialVersionUID即可.

该对的javadocSerializable:

默认的serialVersionUID计算对类细节高度敏感,这些细节可能因编译器实现而异,因此InvalidClassException在反序列化期间可能会导致意外的s.

因此,您必须声明serialVersionUID,因为它为我们提供了更多控制权.

本文对该主题有一些好处.


`serialVersionUID`是*不是*每个类的'唯一标识符'.完全限定的类名是.这是一个*版本*指标.
@Vinothbabu但serialVersionUID是静态的,因此静态变量无法序列化.那么jvm将如何检查版本,而不知道反序列化对象的版本是什么
在这个答案中没有提到的一件事是你可能会盲目地包括`serialVersionUID`而不知道为什么会造成意想不到的后果.汤姆安德森对MetroidFan2002答案的评论解释了这一点:"我会说,如果你不使用序列化进行永久存储,你应该使用@SuppressWarnings而不是增加一个值.它会减少类的混乱,并保留了它的能力. serialVersionUID机制,以保护您免受不兼容的更改."

7> Rupesh..:

原始问题要求'为什么这很重要'和'示例'这Serial Version ID将是有用的.好吧,我找到了一个.

假设您创建一个Car类,将其实例化,并将其写入对象流.扁平的汽车对象在文件系统中存在一段时间.同时,如果Car通过添加新字段来修改类.稍后,当您尝试读取(即反序列化)展平Car对象时,您将获得java.io.InvalidClassException- 因为所有可序列化类都会自动获得唯一标识符.当类的标识符不等于展平对象的标识符时,抛出此异常.如果您真的考虑过它,则会因为添加新字段而抛出异常.您可以通过声明显式serialVersionUID来自行控制版本控制来避免抛出此异常.明确声明您的serialVersionUID(因为不必计算)也有一个小的性能优势.因此,最好在创建它们时将自己的serialVersionUID添加到Serializable类中,如下所示:

public class Car {
    static final long serialVersionUID = 1L; //assign a long value
}


@abbas“一个应该”为什么这么做?请说明其区别。

8> 小智..:

如果您永远不需要将对象序列化为字节数组并发送/存储它们,那么您不必担心它.如果这样做,那么你必须考虑你的serialVersionUID,因为对象的反序列化器会将它与它的类加载器所具有的对象版本相匹配.在Java语言规范中阅读更多相关内容.


如果您不打算序列化对象,为什么它们可以序列化?
@erickson - 父类可以是可序列化的,比如ArrayList,但是你想要自己的对象(比如一个修改过的数组列表)将它用作基础但是永远不会序列化你创建的Collection.
Java语言规范中没有提到它.它在对象版本控制规范中提到.
以下是Java 8 [对象版本控制规范](http://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html)的链接.

9> Paŭlo Eberma..:

如果你在类上得到这个警告,你从未想过序列化,并且你没有自己声明implements Serializable,那通常是因为你继承了一个超类,它实现了Serializable.通常,最好委托给这样的对象而不是使用继承.

所以,而不是

public class MyExample extends ArrayList {

    public MyExample() {
        super();
    }
    ...
}

public class MyExample {
    private List myList;

    public MyExample() {
         this.myList = new ArrayList();
    }
    ...
}

并在相关方法中调用myList.foo()而不是this.foo()(或super.foo()).(这并不适用于所有情况,但仍然经常使用.)

我经常看到人们扩展JFrame等,当他们真的只需要委托给它时.(这也有助于在IDE中自动完成,因为JFrame有数百种方法,当您想在课堂上调用自定义方法时,您不需要这些方法.)

警告(或serialVersionUID)不可避免的一种情况是,从AbstractAction扩展(通常在匿名类中),只添加actionPerformed-method.我认为在这种情况下不应该有警告(因为你通常无法在类的不同版本中对这些匿名类进行可靠的序列化和反序列化),但我不确定编译器如何识别它.


我认为你是对的,对于不合理的构图更有意义,特别是在你讨论像ArrayList这样的类时.但是,许多框架要求人们从可序列化的抽象超类(例如Struts 1.2的ActionForm类或Saxon的ExtensionFunctionDefinition)扩展,在这种情况下,此解决方案是不可行的.我认为你是对的,如果在某些情况下忽略警告会很好(比如你是从一个抽象的可序列化类扩展)
@M_M:当您将大量方法委托给包装对象时,当然使用委托是不合适的.但我想这个案例是设计错误的标志 - 你的类的用户(例如"MainGui")不需要调用包装对象的许多方法(例如JFrame).
当然,如果您将一个类添加为成员,而不是从它继承,您将不得不为您希望使用的成员类的每个方法编写一个包装器方法,这将使它在许多情况下变得不可行.除非java有一个类似于perl的`__AUTOLOAD`的函数,我不知道.
Throwable是可序列化的,并且只有Throwable是可抛出的,因此无法定义不可序列化的异常。委派是不可能的。

10> JegsVala..:

首先,我需要解释序列化.
序列化允许将对象转换为流,通过网络发送该对象或保存到文件或保存到DB以供字母使用.

序列化有一些规则.

仅当对象的类或其超类实现Serializable接口时,该对象才是可序列化的

对象是可序列化的(本身实现了Serializable接口),即使它的超类不是.但是,可序列化类的层次结构中的第一个超类(不实现Serializable接口)必须具有无参数构造函数.如果违反了此规则,readObject()将在运行时生成java.io.InvalidClassException

所有原始类型都是可序列化的.

瞬态字段(具有瞬态修饰符)未被序列化(即,未保存或恢复).实现Serializable的类必须标记不支持序列化的类的瞬态字段(例如,文件流).

静态字段(带有静态修饰符)未序列化.

对象序列化时JAVA Runtime关联称为serialVersionID的序列版本号.

我们需要serialVersionID的地方:在反序列化期间验证发送方和接收方是否与序列化兼容.如果接收方使用不同的serialVersionID加载类,则反序列化将以 InvalidClassCastException结束.
可序列化类可以通过声明名为"serialVersionUID"的字段来显式声明其自己的serialVersionUID,该字段必须是static,final和long类型:

让我们试试这个例子吧.

import java.io.Serializable;    
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;

public String getEmpName() {
    return name;
}
public void setEmpName(String empname) {
    this.empname = empname;
}
public byte getEmpAge() {
    return empage;
}
public void setEmpAge(byte empage) {
    this.empage = empage;
}

public String whoIsThis() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

创建序列化对象

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
    Employee employee = new Employee();
    employee.setEmpName("Jagdish");
    employee.setEmpAge((byte) 30);

    FileOutputStream fout = new 
FileOutputStream("/users/Jagdish.vala/employee.obj");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(employee);
    oos.close();
    System.out.println("Process complete");
}
}

Deserializ对象

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException, 
IOException {
    Employee employee = new Employee();
    FileInputStream fin = new 
    FileInputStream("/users/Jagdish.vala/employee.obj");
    ObjectInputStream ois = new ObjectInputStream(fin);
    employee = (Employee) ois.readObject();
    ois.close();
    System.out.println(employee.whoIsThis());
 }
}    

注意:现在更改Employee类的serialVersionUID并保存:

private static final long serialVersionUID = 4L;

并执行Reader类.不执行Writer类,您将获得异常.

Exception in thread "main" java.io.InvalidClassException: 
com.jagdish.vala.java.serialVersion.Employee; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)



11> 小智..:

要理解字段serialVersionUID的重要性,应该了解序列化/反序列化的工作原理.

当Serializable类对象被序列化时,Java Runtime将序列版本号(称为serialVersionUID)与此序列化对象相关联.在反序列化此序列化对象时,Java Runtime将序列化对象的serialVersionUID与类的serialVersionUID匹配.如果两者都相等,那么只有它继续进行反序列化的进一步过程,否则抛出InvalidClassException.

因此,我们得出结论,为了使序列化/反序列化过程成功,序列化对象的serialVersionUID必须等同于类的serialVersionUID.如果程序员在程序中明确指定serialVersionUID值,那么相同的值将与序列化对象和类相关联,而不管序列化和反序列化平台(例如,序列化可以通过使用sun或类似于windows的平台来完成) MS JVM和反序列化可能位于使用Zing JVM的不同平台Linux上.

但是如果程序员没有指定serialVersionUID,那么在执行任何对象的Serialization\DeSerialization时,Java运行时使用自己的算法来计算它.此serialVersionUID计算算法因JRE而异.对象序列化的环境也可能是使用一个JRE(例如:SUN JVM),而反序列化发生的环境是使用Linux Jvm(zing).在这种情况下,与序列化对象关联的serialVersionUID将与在反序列化环境中计算的类的serialVersionUID不同.反过来反序列化也不会成功.因此,要避免这种情况/问题,程序员必须始终指定Serializable类的serialVersionUID.


该算法没有变化,但稍微不明确.

12> grand johnso..:

不要打扰,默认计算非常好,足以满足99,9999%的情况.如果你遇到问题,你可以 - 正如已经说过的那样 - 引入UID作为需求出现(这是极不可能的)


垃圾。在班级没有变化的情况下就足够了。您有零证据支持“ 99.9999%”。

13> Henrique Ord..:

至于缺少serialVersionUID可能导致问题的示例:

我正在研究这个Java EE应用程序,它由一个使用EJB模块的Web模块组成.Web模块EJB远程调用模块并将POJO该实现Serializable作为参数传递.

这个POJO's类被打包在EJB jar中,并在Web模块的WEB-INF/lib中自己的jar中.它们实际上是同一个类,但是当我打包EJB模块时,我解压缩这个POJO的jar以将它与EJB模块一起打包.

EJB由于我没有声明它,因此对下面的Exception 的调用失败了serialVersionUID:

Caused by: java.io.IOException: Mismatched serialization UIDs : Source
 (Rep.
 IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588)
 = 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52)
 = 6227F23FA74A9A52



14> Archimedes T..:

我通常serialVersionUID在一个上下文中使用:当我知道它将离开Java VM的上下文.

我知道这个,当我使用ObjectInputStreamObjectOutputStream我的应用程序或如果我知道我使用的库/框架将使用它.serialVersionID确保不同版本或供应商的不同Java VM将正确地互操作,或者如果它在VM外部存储和检索,例如HttpSession,即使在重新启动和升级应用服务器期间,会话数据也可以保持.

对于所有其他情况,我使用

@SuppressWarnings("serial")

因为大多数时候默认serialVersionUID就足够了.这包括Exception,HttpServlet.



15> Mukti..:

字段数据表示存储在类中的一些信息.类实现了Serializable接口,因此eclipse自动提供声明serialVersionUID字段.让我们从那里开始设置值1.

如果您不希望发出此警告,请使用以下命令:

@SuppressWarnings("serial")



16> 小智..:

如果CheckStyle可以验证实现Serializable的类上的serialVersionUID具有良好的值,即它与串行版本ID生成器将产生的匹配,那将是很好的.例如,如果你有一个包含大量可序列化DTO的项目,记住要删除现有的serialVersionUID并重新生成它是一件痛苦的事,目前唯一的方法(据我所知)来验证这是为每个类重新生成并比较旧的.这非常非常痛苦.


如果将serialVersionUID始终设置为生成器生成的相同值,则根本不需要它.毕竟,当课程仍然兼容时,它的存在理由是在变化之后保持不变.
原因是不同的编译器为同一个类提出了相同的值.正如javadocs中所解释的那样(上面也回答过),生成的版本很脆弱,即使类可以正确反序列化,也会有所不同.只要您每次在同一个编译器上运行此测试,它应该是安全的.如果您升级jdk并且出现新规则,上帝会帮助您,即使您的代码没有更改.
它不需要匹配`serialver`会产生什么.-1

17> Neethu..:

SerialVersionUID用于对象的版本控制.您也可以在类文件中指定serialVersionUID.不指定serialVersionUID的后果是,当您在类中添加或修改任何字段时,已经序列化的类将无法恢复,因为为新类和旧序列化对象生成的serialVersionUID将不同.Java序列化过程依赖于正确的serialVersionUID来恢复序列化对象的状态,并在serialVersionUID不匹配的情况下抛出java.io.InvalidClassException

阅读更多:http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ



18> roottravelle..:

为什么在Java中使用SerialVersionUID内部Serializable类?

在此期间serialization,Java运行时为类创建版本号,以便稍后可以对其进行反序列化.此版本号SerialVersionUID在Java中称为.

SerialVersionUID用于版本化序列化数据.如果类SerialVersionUID与序列化实例匹配,则只能对类进行反序列化.当我们不在SerialVersionUID我们的类中声明时,Java运行库为我们生成它,但不推荐它.建议将其声明SerialVersionUIDprivate static final long变量以避免默认机制.

当您Serializable通过实现标记接口声明类java.io.Serializable时,Java运行时通过使用默认的序列化机制将该类的实例持久保存到磁盘中,前提是您尚未使用Externalizable接口自定义该过程.

另请参见为什么在Java中的Serializable类中使用SerialVersionUID

代码:javassist.SerialVersionUID



19> schnell18..:

如果你想修改大量没有设置serialVersionUID的类,同时保持与旧类的兼容性,那么像IntelliJ Idea,Eclipse这样的工具就会因为生成随机数而无法在一堆文件上工作.一气呵成.我提出了以下bash脚本(我很抱歉Windows用户,考虑购买Mac或转换为Linux)以轻松修改serialVersionUID问题:

base_dir=$(pwd)                                                                  
src_dir=$base_dir/src/main/java                                                  
ic_api_cp=$base_dir/target/classes                                               

while read f                                                                     
do                                                                               
    clazz=${f//\//.}                                                             
    clazz=${clazz/%.java/}                                                       
    seruidstr=$(serialver -classpath $ic_api_cp $clazz | cut -d ':' -f 2 | sed -e 's/^\s\+//')
    perl -ni.bak -e "print $_; printf qq{%s\n}, q{    private $seruidstr} if /public class/" $src_dir/$f
done

你保存这个脚本,比如说add_serialVersionUID.sh给〜/ bin.然后在Maven或Gradle项目的根目录中运行它,如:

add_serialVersionUID.sh < myJavaToAmend.lst

此.lst包含以下列格式添加serialVersionUID的java文件列表:

com/abc/ic/api/model/domain/item/BizOrderTransDO.java
com/abc/ic/api/model/domain/item/CardPassFeature.java
com/abc/ic/api/model/domain/item/CategoryFeature.java
com/abc/ic/api/model/domain/item/GoodsFeature.java
com/abc/ic/api/model/domain/item/ItemFeature.java
com/abc/ic/api/model/domain/item/ItemPicUrls.java
com/abc/ic/api/model/domain/item/ItemSkuDO.java
com/abc/ic/api/model/domain/serve/ServeCategoryFeature.java
com/abc/ic/api/model/domain/serve/ServeFeature.java
com/abc/ic/api/model/param/depot/DepotItemDTO.java
com/abc/ic/api/model/param/depot/DepotItemQueryDTO.java
com/abc/ic/api/model/param/depot/InDepotDTO.java
com/abc/ic/api/model/param/depot/OutDepotDTO.java

此脚本使用引擎盖下的JDK serialVer工具.因此,请确保您的$ JAVA_HOME/bin位于PATH中.


给我一个主意:在发布之前,请始终使用这样的工具(永远不要手动)来重新生成串行版本uid-这样,您可以避免忘记对由于实际情况而更改了其串行版本uid的类进行更改不兼容的更改。手动跟踪该信息非常困难。

20> Geek..:

这个问题在Joshua Bloch的Effective Java中有很好的记录.一本非常好的书,必读.我将概述以下一些原因:

序列化运行时为每个可序列化类提供了一个名为Serial版本的编号.此编号称为serialVersionUID.现在这个数字后面有一些数学,它基于类中定义的字段/方法出来.对于同一个类,每次都会生成相同的版本.在反序列化期间使用此数字来验证序列化对象的发送方和接收方是否已加载与序列化兼容的该对象的类.如果接收者为具有与相应发送者类的serialVersionUID不同的对象加载了一个类,则反序列化将导致InvalidClassException.

如果类是可序列化的,您还可以通过声明名为"serialVersionUID"的字段来明确声明自己的serialVersionUID,该字段必须是static,final和long类型.大多数IDE都像Eclipse一样帮助你生成那个长字符串.



21> Naved Ali..:

每次对象被序列化时,对象都会标记对象类的版本ID号.此ID称为serialVersionUID,它是根据有关类结构的信息计算的.假设您创建了一个Employee类,它的版本号为#333(由JVM分配),现在当您序列化该类的对象时(假设为Employee对象),JVM会将UID指定为#333.

考虑一种情况 - 将来您需要编辑或更改您的类,在这种情况下,当您修改它时,JVM将为其分配一个新的UID(假设#444).现在,当您尝试反序列化employee对象时,JVM会将序列化对象的(Employee对象)版本ID(#333)与类的名称进行比较,即#444(因为它已被更改).相比之下,JVM会发现两个版本的UID都不同,因此反序列化将失败.因此,如果每个类的serialVersionID由程序员自己定义.即使该类在将来进化,它也是一样的,因此即使类被更改,JVM也总是会发现该类与序列化对象兼容.有关更多信息,请参阅HEAD FIRST JAVA的第14章.

推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有