0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

static属性为什么不会被序列化

Android编程精选 来源:椰子Tyshawn 作者:椰子Tyshawn 2022-07-15 11:03 次阅读

做服务化,需要把所有model包里的类都实现Serializable接口, 同时还要显示指定serialVersionUID的值。听到这个需求,我脑海里就突然出现了好几个问题,比如说:

序列化和反序列化是什么?

实现序列化和反序列化为什么要实现Serializable接口?

实现Serializable接口就算了,为什么还要显示指定serialVersionUID的值?

我要为serialVersionUID指定个什么值?

下面我们来一一解答这几个问题。

序列化和反序列化

序列化:把对象转换为字节序列的过程称为对象的序列化。

反序列化:把字节序列恢复为对象的过程称为对象的反序列化。

什么时候需要用到序列化和反序列化呢?

当我们只在本地JVM里运行下Java实例,这个时候是不需要什么序列化和反序列化的, 但当我们需要将内存中的对象持久化到磁盘, 数据库中时,当我们需要与浏览器进行交互时, 当我们需要实现RPC时,这个时候就需要序列化和反序列化了。

前两个需要用到序列化和反序列化的场景,是不是让我们有一个很大的疑问? 我们在与浏览器交互时,还有将内存中的对象持久化到数据库中时,好像都没有去进行序列化和反序列化,因为我们都没有实现Serializable接口, 但一直正常运行。

下面先给出结论:

只要我们对内存中的对象进行持久化或网络传输, 这个时候都需要序列化和反序列化.

理由:

服务器与浏览器交互时真的没有用到Serializable接口吗? JSON格式实际上就是将一个对象转化为字符串, 所以服务器与浏览器交互时的数据格式其实是字符串, 我们来看来String类型的源码:

publicfinalclassString
implementsjava.io.Serializable,Comparable,CharSequence{
/**Thevalueisusedforcharacterstorage.*/
privatefinalcharvalue[];

/**Cachethehashcodeforthestring*/
privateinthash;//Defaultto0

/**useserialVersionUIDfromJDK1.0.2forinteroperability*/
privatestaticfinallongserialVersionUID=-6849794470754667710L;

......
}

String类型实现了Serializable接口,并显示指定serialVersionUID的值。

然后我们再来看对象持久化到数据库中时的情况,Mybatis数据库映射文件里的insert代码:


INSERTINTOt_user(name,age)VALUES(#{name},#{age})

实际上我们并不是将整个对象持久化到数据库中, 而是将对象中的属性持久化到数据库中, 而这些属性都是实现了Serializable接口的基本属性。

实现序列化和反序列化为什么要实现Serializable接口?

在Java中实现了Serializable接口后,JVM会在底层帮我们实现序列化和反序列化, 如果我们不实现Serializable接口, 那自己去写一套序列化和反序列化代码也行, 至于具体怎么写, Google一下你就知道了。

实现Serializable接口就算了, 为什么还要显示指定serialVersionUID的值?

如果不显示指定serialVersionUID,JVM在序列化时会根据属性自动生成一个serialVersionUID, 然后与属性一起序列化,再进行持久化或网络传输. 在反序列化时,JVM会再根据属性自动生成一个新版serialVersionUID,然后将这个新版serialVersionUID与序列化时生成的旧版serialVersionUID进行比较, 如果相同则反序列化成功, 否则报错.

如果显示指定了serialVersionUID, JVM在序列化和反序列化时仍然都会生成一个serialVersionUID, 但值为我们显示指定的值, 这样在反序列化时新旧版本的serialVersionUID就一致了。

在实际开发中, 不显示指定serialVersionUID的情况会导致什么问题? 如果我们的类写完后不再修改, 那当然不会有问题, 但这在实际开发中是不可能的,我们的类会不断迭代, 一旦类被修改了,那旧对象反序列化就会报错. 所以在实际开发中, 我们都会显示指定一个serialVersionUID, 值是多少无所谓, 只要不变就行。

写个实例测试下:

User类

不显示指定serialVersionUID.

publicclassUserimplementsSerializable{
privateStringname;
privateIntegerage;
publicStringgetName(){
returnname;
}

publicvoidsetName(Stringname){
this.name=name;
}

publicIntegergetAge(){
returnage;
}

publicvoidsetAge(Integerage){
this.age=age;
}

@Override
publicStringtoString(){
return"User{"+
"name='"+name+'''+
",age="+age+
'}';
}
}

测试类

先进行序列化, 再进行反序列化.

publicclassSerializableTest{
privatestaticvoidserialize(Useruser)throwsException{
ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream(newFile("D:\111.txt")));
oos.writeObject(user);
oos.close();
}

privatestaticUserdeserialize()throwsException{
ObjectInputStreamois=newObjectInputStream(newFileInputStream(newFile("D:\111.txt")));
return(User)ois.readObject();
}

publicstaticvoidmain(String[]args)throwsException{
Useruser=newUser();
user.setName("tyshawn");
user.setAge(18);
System.out.println("序列化前的结果:"+user);

serialize(user);
UserdUser=deserialize();
System.out.println("反序列化后的结果:"+dUser);
}
}

结果

先注释掉反序列化代码,执行序列化代码,然后User类新增一个属性sex。

publicclassUserimplementsSerializable{
privateStringname;
privateIntegerage;
privateStringsex;
publicStringgetName(){
returnname;
}

publicvoidsetName(Stringname){
this.name=name;
}

publicIntegergetAge(){
returnage;
}

publicvoidsetAge(Integerage){
this.age=age;
}

publicStringgetSex(){
returnsex;
}

publicvoidsetSex(Stringsex){
this.sex=sex;
}

@Override
publicStringtoString(){
return"User{"+
"name='"+name+'''+
",age="+age+
",sex='"+sex+'''+
'}';
}
}

再注释掉序列化代码执行反序列化代码,最后结果如下:

序列化前的结果: User{name='tyshawn', age=18}Exception in thread "main" java.io.InvalidClassException: org.tyshawn.SerializeAndDeserialize.User; local class incompatible: stream classdesc serialVersionUID = 1035612825366363028, local class serialVersionUID = -1830850955895931978报错结果为序列化与反序列化产生的serialVersionUID不一致。

接下来我们在上面User类的基础上显示指定一个serialVersionUID。

privatestaticfinallongserialVersionUID=1L;

再执行上述步骤, 测试结果如下:

序列化前的结果: User{name='tyshawn', age=18}反序列化后的结果: User{name='tyshawn', age=18, sex='null'}

显示指定serialVersionUID后就解决了序列化与反序列化产生的serialVersionUID不一致的问题。

Java序列化的其他特性

先说结论, 被transient关键字修饰的属性不会被序列化, static属性也不会被序列化。

我们来测试下这个结论:

User类

publicclassUserimplementsSerializable{
privatestaticfinallongserialVersionUID=1L;
privateStringname;
privateIntegerage;
privatetransientStringsex;
privatestaticStringsignature="你眼中的世界就是你自己的样子";
publicStringgetName(){
returnname;
}

publicvoidsetName(Stringname){
this.name=name;
}

publicIntegergetAge(){
returnage;
}

publicvoidsetAge(Integerage){
this.age=age;
}

publicStringgetSex(){
returnsex;
}

publicvoidsetSex(Stringsex){
this.sex=sex;
}

publicstaticStringgetSignature(){
returnsignature;
}

publicstaticvoidsetSignature(Stringsignature){
User.signature=signature;
}

@Override
publicStringtoString(){
return"User{"+
"name='"+name+'''+
",age="+age+
",sex='"+sex+'''+
",signature='"+signature+'''+
'}';
}
}

测试类

publicclassSerializableTest{
privatestaticvoidserialize(Useruser)throwsException{
ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream(newFile("D:\111.txt")));
oos.writeObject(user);
oos.close();
}

privatestaticUserdeserialize()throwsException{
ObjectInputStreamois=newObjectInputStream(newFileInputStream(newFile("D:\111.txt")));
return(User)ois.readObject();
}
publicstaticvoidmain(String[]args)throwsException{
Useruser=newUser();
user.setName("tyshawn");
user.setAge(18);
user.setSex("man");
System.out.println("序列化前的结果:"+user);
serialize(user);
UserdUser=deserialize();
System.out.println("反序列化后的结果:"+dUser);
}
}

结果

先注释掉反序列化代码, 执行序列化代码, 然后修改User类signature = “我的眼里只有你”, 再注释掉序列化代码执行反序列化代码, 最后结果如下:

序列化前的结果: User{name='tyshawn', age=18, sex='man', signature='你眼中的世界就是你自己的样子'}反序列化后的结果: User{name='tyshawn', age=18, sex='null', signature='我的眼里只有你'}

static属性为什么不会被序列化?

因为序列化是针对对象而言的,而static属性优先于对象存在,随着类的加载而加载, 所以不会被序列化。

看到这个结论,是不是有人会问,serialVersionUID也被static修饰,为什么serialVersionUID会被序列化? 其实serialVersionUID属性并没有被序列化,JVM在序列化对象时会自动生成一个serialVersionUID,然后将我们显示指定的serialVersionUID属性值赋给自动生成的serialVersionUID。

原文标题:Java 序列化和反序列化,为什么要实现 Serializable 接口?

文章出处:【微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

审核编辑:彭静

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    7573

    浏览量

    148206
  • 网络传输
    +关注

    关注

    0

    文章

    123

    浏览量

    17197
  • static
    +关注

    关注

    0

    文章

    33

    浏览量

    10225

原文标题:Java 序列化和反序列化,为什么要实现 Serializable 接口?

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何使用Serde进行序列化和反序列化

    Serde 是一个用于序列化和反序列化 Rust 数据结构的库。它支持 JSON、BSON、YAML 等多种格式,并且可以自定义序列化和反序列化方式。Serde 的特点是代码简洁、易于
    的头像 发表于 09-30 17:09 770次阅读

    序列化哈希表到文件

    BinarySerialize {//把哈希表对象序列化到文件public static void Serialize(String strFile, Hashtable ht){using
    发表于 06-18 18:28

    Java序列化的机制和原理

    本文讲解了Java序列化的机制和原理。从文中你可以了解如何序列化一个对象,什么时候需要序列化以及Java序列化的算法。AD:WOT2014课程推荐:实战MSA:用开源软件搭建微服务系统
    发表于 07-10 07:27

    LabVIEW序列化编程,可做通用配置架构

    LabVIEW序列化编程,可做通用配置架构[img=110,0][/img][img=110,0][/img]
    发表于 04-23 16:47

    Virtex ISERDES_NODELAY对快速4线总线进行反序列化怎么实现?

    你好朋友。我想使用Virtex ISERDES_NODELAY对快速4线总线进行反序列化。总线大约为700 MHz。我想确保反序列化的信号不是异相的。我的意思是,如果其中一个ISERDES由于内部路由延迟而稍后将复位,则反序列化
    发表于 06-01 16:54

    c语言序列化和反序列化有何区别

    这里写自定义目录标题c语言序列化和反序列化tplut.htplut.c测试代码参考c语言序列化和反序列化网络调用,数据传输都需要把数据序列化
    发表于 07-14 07:32

    关于c语言序列化和反序列化的知识点看完你就懂了

    关于c语言序列和反序列化的知识点你就懂了
    发表于 10-15 08:47

    SpringMVC JSON框架的自定义序列化与反序列化

    ,那么jackson的@JsonSerialize就不会有触发入口了,我们来看看fastjson的处理方式。自定义序列化相应的,使用fastjson会有相应的配置类,示例如下:/** * 统一输出
    发表于 10-10 16:02

    linux内核如何为imx8x添加序列化器和反序列化器驱动程序?

    当我阅读 AN13275 文档“How to enable linux BSP L5.4 on a new imx8/8x board”时,有一个关于在下表中添加序列化器、解串器驱动程序的问题这些
    发表于 03-15 06:48

    java序列化和反序列化范例和JDK类库中的序列化API

    一、序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化。 把字节序列恢复为对象的过程称为对象的反
    发表于 09-27 10:13 6次下载

    C#实现对象序列化的三种方式是什么

    很多小伙伴一提到序列化,都会想到二进制序列化,但其实序列化并不仅仅只是二进制序列化,我们常说的对象序列化有三种方式,分别是二进制
    的头像 发表于 02-22 16:11 613次阅读
    C#实现对象<b class='flag-5'>序列化</b>的三种方式是什么

    python序列化对象

    序列化对象:将对象转换为可以存储或传输的形式。 (1) 用于存储:将对象的字节序列存储到文件中,程序退出后不会消失,便于后续使用。
    的头像 发表于 03-10 09:57 2116次阅读

    python序列化对象

    序列化对象:将对象转换为可以存储或传输的形式。 (1) 用于存储:将对象的字节序列存储到文件中,程序退出后不会消失,便于后续使用。 (2) 用于传输:发送方把对象转换为字节
    的头像 发表于 04-06 15:08 470次阅读

    什么是序列化 为什么要序列化

    什么是序列化? “序列化”(Serialization )的意思是将一个对象转化为字节流。 这里说的对象可以理解为“面向对象”里的那个对象,具体的就是存储在内存中的对象数据。 与之相反的过程是“反序列化
    的头像 发表于 09-14 17:22 1309次阅读
    什么是<b class='flag-5'>序列化</b> 为什么要<b class='flag-5'>序列化</b>

    如何用C语言进行json的序列化和反序列化

    json是目前最为流行的文本数据传输格式,特别是在网络通信上广泛应用,随着物联网的兴起,在嵌入式设备上,也需要开始使用json进行数据传输,那么,如何快速简洁地用C语言进行json的序列化和反序列化
    的头像 发表于 10-07 11:05 763次阅读