java序列化,看这篇就够了

news2025/2/25 15:10:27

面试官:兄弟,说说你对transient的理解和感悟

哪吒:what?还有感悟?

先说结论,在序列化、反序列化时,被transient关键字修饰的成员属性变量不会被序列化。

面试官:这就完了?
在这里插入图片描述
哪吒:面试官明显不是很满意,这怎么能够。

追根溯源,先说一下序列化与反序列化。

一、序列化是啥?

1、序列化和反序列化定义

Java序列化是指把Java对象转换为字节序列的过程。

Java反序列化是指把字节序列恢复为Java对象的过程。

2、面试官没听懂,有点迷啊!

简而言之,序列化是将Java对象转变为字节序列,便于持久化到本地磁盘,避免程序运行结束后对象从内存中消失,字节序列也方便在网络中传输。

序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。

在这里插入图片描述

3、序列化和反序列化的作用

(1)序列化作用

在传递和保存对象时,保存对象的完整性和可传递性。
对象转换为有序字节流,可以在网络上传输或者保存在本地文件(一般json/xml文件居多)中。

(2)反序列化作用

根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。

二、序列化和反序列化的优缺点

1、优点

  1. 将对象转为字节流存储到硬盘上,当JVM停机的时候,字节流还会在硬盘上等待,等待下一次JVM启动,把序列化的对象,通过反序列化转为原来的对象,并且序列化的二进制序列能够减少存储空间(永久性保存对象)。
  2. 序列化为字节流形式的对象可以进行网络传输(二进制形式)。
  3. 通过序列化可以在进程间传递对象。

2、缺点

(1)无法跨语言

无法跨语言是Java序列化最致命的问题。

对于跨进程的服务调用,服务提供者可能是Java之外的其它语言,当我们需要和其它语言交互时,Java序列化就难以胜任。

事实上,目前几乎所有流行的Java RPC通信框架,都没有使用Java序列化作为编解码框架,原因就是它无法跨语言,而这些RPC框架往往需要支持跨语言调用。

Java RPC通信框架简介

RPC是远程过程调用的简称,广泛应用在大规模分布式应用中,作用是有助于系统的垂直拆分,使系统更易扩展。Java中RPC框架比较多,各有特色,广泛使用的有RMI、Hession、Dubbo等。

1、RMI(远程方法调用):

JAVA自带的远程方法调用工具,不过有一定的局限性,毕竟是JAVA语言最开始时的设计,后来很多框架的原理都基于RMI。

2、Hessian(基于HTTP的远程方法调用):

基于HTTP协议传输,在性能方面还不够完美,负载均衡和失效转移依赖于应用的负载均衡器,Hessian的使用则与RMI类似,区别在于淡化了Registry的角色,通过显示的地址调用,利用HessianProxyFactory根据配置的地址create一个代理对象,另外还要引入Hessian的Jar包。

3、Dubbo(淘宝开源的基于TCP的RPC框架)

Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

在这里插入图片描述

(2)序列化后流的长度比通过缓冲区处理要大的多。

(3)序列化性能太低

三、序列化使用场景

  1. 像银行卡、密码这些字段不能被序列化;
  2. 将对象存储到文件中时进行序列化,从文件中读取对象时需要反序列化;
  3. 分布式传递对象,或者网络传输,需要序列化;
  4. 存入缓存数据库(如 Redis)时需要用到序列化,将对象从缓存数据库中读取出来需要反序列化;

四、序列化和反序列化的注意事项

1、Java序列化的方式

实现 Serializable 接口:可以自定义 writeObject、readObject、writeReplace、readResolve 方法,会通过反射调用。

实现 Externalizable 接口,它是Serializable接口的子类,用户要实现的writeExternal()和readExternal() 方法,用来决定如何序列化和反序列化。因为序列化哪些字段,需要方法指定,所以transient在这里无效。

2、序列化ID问题

虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。

3、静态字段不会序列化

序列化时不保存静态变量,这是因为序列化保存的是对象的状态,静态变量属于类的状态,因此序列化并不保存静态变量。

4、transient

transient代表对象的临时数据。

如果你不想让对象中的某个成员被序列化可以在定义它的时候加上 transient 关键字进行修饰,这样,在对象被序列化时其就不会被序列化。

transient 修饰过的成员反序列化后将赋予默认值,即 0 或 null。

有些时候像银行卡号这些字段是不希望在网络上传输的,transient的作用就是把这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。

5、父类的序列化

当一个父类实现序列化,子类自动实现序列化;而子类实现了 Serializable 接口,父类也需要实现Serializable 接口。

6、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化

7、并非所有的对象都可以序列化

(1)安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;

(2)资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现;

8、序列化解决深拷贝问题

如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存,这是能用序列化解决深拷贝的重要原因。

五、通过代码体验一下

1、实体类

package com.guor.bean;

import lombok.Data;

import java.io.Serializable;

@Data
public class User implements Serializable {

    private Integer id;

    private String username;

    private Integer age;

    private transient String password;
}

2、ObjectOutputStream实现序列化和ObjectInputStream实现反序列化

package com.guor.test;

import com.guor.bean.User;

import java.io.*;

public class TransientTest {
    public static void main(String[] args) {
        try {
            SerializeUser();
            DeSerializeUser();
        } catch (IOException e) {
            e.printStackTrace();
        }catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //序列化
    private static void SerializeUser() throws IOException{
        User user = new User();
        user.setId(1);
        user.setUsername("哪吒编程");
        user.setAge(28);
        user.setPassword("123456");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D://data.txt"));
        oos.writeObject(user);
        oos.close();
        System.out.println("普通字段序列化:username=  "+user.getUsername());
        System.out.println("添加了transient关键字序列化:password=  "+user.getPassword());
    }

    //反序列化
    private static void DeSerializeUser() throws IOException, ClassNotFoundException {
        File file = new File("D://data.txt");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        User user = (User)ois.readObject();
        System.out.println("普通字段反序列化:username=  "+user.getUsername());
        System.out.println("添加了transient关键字反序列化:password=  "+user.getPassword());
    }
}

3、控制台输出

当实体类未实现Serializable时运行会报错,并抛出NotSerializableException异常:
在这里插入图片描述
)
为什么会这样呢?跟踪源码一探究竟!

public final void writeObject(Object obj) throws IOException {
   if (enableOverride) {
        writeObjectOverride(obj);
        return;
    }
    try {
        writeObject0(obj, false);
    } catch (IOException ex) {
        if (depth == 0) {
            writeFatalException(ex);
        }
        throw ex;
    }
}

如果一个对象既不是字符串、数组、枚举,也没有实现Serializable接口,在序列化时就会抛出NotSerializableException异常

private void writeObject0(Object obj, boolean unshared)
        throws IOException {
        
   ...
   
   if (obj instanceof String) {
       writeString((String) obj, unshared);
   } else if (cl.isArray()) {
       writeArray(obj, desc, unshared);
   } else if (obj instanceof Enum) {
       writeEnum((Enum<?>) obj, desc, unshared);
   } else if (obj instanceof Serializable) {
       writeOrdinaryObject(obj, desc, unshared);
   } else {
       if (extendedDebugInfo) {
           throw new NotSerializableException(
               cl.getName() + "\n" + debugInfoStack.toString());
       } else {
           throw new NotSerializableException(cl.getName());
       }
   }
   
   ...
   

在这里插入图片描述
从上述代码看,Serializable也仅仅是起到了一个标识作用,表示当前的bean是支持序列化和反序列化的。

正常情况下:

序列化文件:
在这里插入图片描述
控制台显示:
在这里插入图片描述

六、serialVersionUID

我记得实体类在序列化的时候,要写一个private static final long serialVersionUID = 1L;来着,没写也没问题啊。
在这里插入图片描述
在实体类添加一个属性address,对上面生成的D://data.txt文件,再反序列化一次,看看效果。
在这里插入图片描述

从红线部分提示可以看出两点:

  1. 在进行序列化、反序列化时,程序自动生成了一个serialVersionUID;
  2. 前后序列号不相同;

我觉得只要前后序列号相同,就可以反序列化成功,序列化号 serialVersionUID 属于版本控制的作用。

如果上图能够给我一个再来一次的机会!
在这里插入图片描述

package com.guor.bean;

import lombok.Data;

import java.io.Serializable;

@Data
public class User implements Serializable {

    private static final long serialVersionUID = -3796120637328232911L;

    private Integer id;

    private String username;

    private Integer age;

    private transient String password;

	// 反序列化时,后添加的
    private String address;
}

在这里插入图片描述



哪吒精品系列文章

Java学习路线总结,搬砖工逆袭Java架构师

10万字208道Java经典面试题总结(附答案)

Java基础教程系列

SQL性能优化的21个小技巧

mysql索引详解

MySql基础知识总结(SQL优化篇)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/39649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flutter高仿微信-第51篇-群聊-修改群名

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 实现代码&#xff1a; //修改群名 void _updateGroupName(){bool isOwner fals…

Multi-Interest Network with Dynamic Routing forRecommendation at Tmall 论文阅读笔记

1. ABSTRACT 1.1 Industrial recommender systems &#xff08;1&#xff09;工业推荐系统通常由匹配阶段和排名阶段组成&#xff1b; &#xff08;2&#xff09;匹配阶段&#xff1a;检索与用户兴趣相关的候选项&#xff1b; &#xff08;3&#xff09;排名阶段&#xff1a;…

Spring Cloud OpenFeign - - - > 日志配置

项目源码地址&#xff1a;https://download.csdn.net/download/weixin_42950079/87168704 OpenFeign 有 4 种日志级别&#xff1a; NONE: 不记录任何日志&#xff0c;是OpenFeign默认日志级别&#xff08;性能最佳&#xff0c;适用于生产环境&#xff09;。BASIC: 仅记录请求方…

BT - Unet:生物医学图像分割的自监督学习框架

BT-Unet采用Barlow twin方法对U-Net模型的编码器进行无监督的预训练减少冗余信息&#xff0c;以学习数据表示。之后&#xff0c;对完整网络进行微调以执行实际的分割。 BT-Unet由 Indian Institute of Information Technology Allahabad开发&#xff0c;发布在2022年的JML上 …

相关性质和条件变量-ReentrantLock详解(2)-AQS-并发编程(Java)

文章目录1 可重入2 可打断3 公平锁4 条件变量4.1 await()4.1.1 主方法4.1.2 addConditionWaiter()4.1.3 isOnSyncQueue()4.1.4 checkInterruptWhileWaiting()4.2 signal()4.2.1 主方法4.2.2 doSignal()4.2.3 transferForSignal()5 后记1 可重入 可重入在加锁中体现代码如下&am…

零经验,小白变大厨!

平时煮泡面都会翻车的老王      昨天在朋友圈po了一组美食图      朋友小聚,20分钟搞定一桌菜,嘻嘻。      我点开一看,嚯!      红烧里脊、糖醋排骨、油焖大虾、剁椒鱼头……个顶个的硬菜,而且色泽诱人看起来很好吃的样子,关键是居然20分钟搞定?      难…

2022 高教杯数学建模C题古代玻璃制品的成分分析与鉴别回顾及总结

2022 高教杯数学建模C题古代玻璃制品的成分分析与鉴别回顾及总结 Paper & Code&#xff1a;https://github.com/Fly-Pluche/2022-mathematical-modeling-C 希望可以施舍几个star⭐️ 国赛分工 我们三人都有主要的分工: 队员A主要负责二&#xff0c;三问的求解以及代码的编…

被问到可重入锁条件队列,看这一篇就够了!|原创

本文深入解读了高频面试点——ReentrantLock的条件队列使用方法及其原理。源码有详细注释&#xff0c;建议收藏阅读。点击上方“后端开发技术”&#xff0c;选择“设为星标” &#xff0c;优质资源及时送达Jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantL…

用HTML+CSS做一个简单的新闻门户 1页网页

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 茶文化网站 | 中华传统文化题材 | 京剧文化水墨风书画 | 中国民间年画文化艺术网站 | 等网站的设计与制作 | HTML期末大学生网页设计作业&#xff0c;…

Web前端大作业—电影网页介绍8页(html+css+javascript) 带登录注册表单

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 精彩专栏推荐&#x1f4…

DevOps初学者的指南——阿里出品学习图册带你掌握高薪技术!

开篇 你是否想开始学习DevOps&#xff0c;或者愿意通过增加DevOps这一技能来转变你的职业生涯&#xff1f; 如果你的答案是肯定的&#xff0c;那么你就来对地方了 从初创企业到跨国企业&#xff0c;技术行业的每个细分领域都在改变其软件开发方法。DevOps工具和实践惊人地减…

【mysql 高级】explain的使用及explain包含字段的含义

explain的使用及explain包含字段的含义1.id2. select_type3.table4.type5.possible_keys6.key7.key_len8.ref9.rows10.Extra使用explain关键字可以模拟优化器执行SQL语句&#xff0c;从而知道MySQL是如何处理你的SQL语句的&#xff0c;从而分析你的查询语句或是表结构的性能瓶颈…

面向OLAP的列式存储DBMS-10-[ClickHouse]的常用数组操作

参考ClickHouse 中的数据查询以及各种子句 ClickHouse 数组的相关操作函数&#xff0c;一网打尽 在关系型数据库里面我们一般都不太喜欢用数组&#xff0c;但是在 ClickHouse 中数组会用的非常多&#xff0c;并且操作起来非常简单。ClickHouse 里面提供了非常多的函数&#x…

文本生成视频Make-A-Video,根据一句话就能一键生成视频 Meta新AI模型

Meta公司&#xff08;原Facebook&#xff09;在今年9月29日首次推出一款人工智能系统模型&#xff1a;Make-A-Video&#xff0c;可以从给定的文字提示生成短视频。 Make-A-Video研究基于文本到图像生成技术的最新进展&#xff0c;该技术旨在实现文本到视频的生成&#xff0c;可…

[附源码]Python计算机毕业设计高校第二课堂管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

第十章 二叉树的各种遍历

第十章&#xff1a;二叉树的前、中、后序遍历前期准备:一、前序遍历1、遍历的思路2、遍历代码3、遍历图示二、中序遍历1、遍历的思路2、遍历代码三、后序遍历1、遍历的思路2、遍历代码三、遍历的应用1、计算二叉树中的节点个数2、二叉树叶子节点的个数3、二叉树的深度4、二叉树…

EMC原理-传导(共模、差模)与辐射(近场、远场)详解

目录&#xff1a; 第一章、EMC概念介绍 第二章、感应干扰(近场) 第三章、辐射干扰(远场) 第四章、差模干扰 第五章、共模干扰 ------------------------------------------------------------------------------------------------------------------------ 第一章、EMC…

ceph块存储在线扩容

记录&#xff1a;339 场景&#xff1a;在CentOS 7.9操作系统上&#xff0c;部署ceph-13.2.10集群。应用ceph块设备(ceph block device)&#xff1b;主要是创建ceph块存储和在线扩容相关操作。 版本&#xff1a; 操作系统&#xff1a;CentOS 7.9 ceph版本&#xff1a;ceph-1…

牛顿法(牛顿拉夫逊)配电网潮流计算matlab程序

牛顿法配电网潮流计算matlab程序 传统牛顿—拉夫逊算法&#xff0c;简称牛顿法&#xff0c;是将潮流计算方程组F(X)0&#xff0c;进行泰勒展开。因泰勒展开有许多高阶项&#xff0c;而高阶项级数部分对计算结果影响很小&#xff0c;当忽略一阶以上部分时&#xff0c;可以简化对…

向NS-3添加新模块_ns3.37添加新模块_ns3.37不同版本模块移植

使用ns3的时候&#xff0c;我们需要调用很多模块&#xff0c;比如对wifi的简单功能进行仿真时&#xff1a; ns-3.35_third.cc_ns-3网络仿真工具wifi脚本解析_wifi脚本网络拓扑_ns-3third脚本全注释_基础ns-3_ns-3入门_ns-3third脚本解析_Part1_Mr_liu_666的博客-CSDN博客Intro…