Java序列化总结

Java 序列化 对于 Java 这种面向对象编程语言来说,我们序列化的都是对象(Object)也就是实例化后的类(Class),但是在 C++这种半面向对象的语言中,struct(结构体)定义的是数据结构类型,而 class 对应的是对象类型。因为,OSI 七层协议模型中的应用层、表示层和会话层对应的都是 TCP/IP 四层模型中的应用层,所以序列化协议属于 TCP/IP 协议应用层的一部分。修饰的变量是静态变量,属于类而非类的实例,本身是不会被序列化的。,因为这通常意味着序列化的类的定义已经发生了更改,可能不再兼容。 阅读详情
前一段时间写的关于集合类源码分析的博客中其实一直没有提到两个方法,那就是writeObject和readObject方法。这两个方法涉及到序列化的内容,这篇博文总结遇到过的和序列化相关的内容。

     什么是序列化?

     序列化是将对象的状态信息转化为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后可以通过存储区中读取或反序列化对象的状态重新创建对象。

     为什么要序列化?

     有两个最重要的原因促使对序列化的使用:一个原因是将对象的状态保持在存储媒体中,以便可以在以后重新创建精确的副本;另一个原因是通过值将对象从一个应用程序域发送到另一个应用程序域中。例如,在网络中传输的数据都必须要序列化。

     Java中的序列化

     Java中的序列化机制能够将一个实例对象的状态信息写入到一个字节流中,使其可以通过socket进行传输或者持久化存储到数据库或文件系统中,然后再需要的时候可以读取字节流中的信息重构一个相同的对象。序列化在Java中有着广泛的应用,RMI、Hessian等技术都是以此为基础的。

     下面是一些序列化涉及到的内容的例子。

     UserInfo类是下面序列化例子中都要用到的一个保存基本信息的类。

复制代码
 1 public class UserInfo implements Serializable {
 2 
 3     private static final long serialVersionUID = 1L;
 4     public static String defaultPostcode = "310000";
 5     private int age;
 6     private String name;
 7 
 8     public int getAge() {
 9         return age;
10     }
11 
12     public void setAge(int age) {
13         this.age = age;
14     }
15 
16     public String getName() {
17         return name;
18     }
19 
20     public void setName(String name) {
21         this.name = name;
22     }
23 
24     public static String getDefaultPostcode() {
25         return defaultPostcode;
26     }
27 
28     public static void setDefaultPostcode(String defaultPostcode) {
29         UserInfo.defaultPostcode = defaultPostcode;
30     }
31 
32     public void desSelf() {
33         System.out.println("Default Postcode: " + getDefaultPostcode());
34         System.out.println("Age: " + getAge());
35         System.out.println("Name: " + getName());
36     }
37 }
复制代码

     结合UserInfo的内容,先看下面这个main方法。

复制代码
 1 public static void main(String[] args) throws IOException, ClassNotFoundException {
 2         FileOutputStream fos = new FileOutputStream("temp.out");
 3         ObjectOutputStream oos = new ObjectOutputStream(fos);
 4         UserInfo user = new UserInfo();
 5         user.setAge(25);
 6         user.setName("Tom");
 7         System.out.println("Before Serialize");
 8         user.desSelf();
 9         // 保存对象后修改了DefaultPostcode
10         UserInfo.setDefaultPostcode("110");
11         oos.writeObject(user);
12         oos.flush();
13         FileInputStream fis = new FileInputStream("temp.out");
14         ObjectInputStream ois = new ObjectInputStream(fis);
15         user = (UserInfo)ois.readObject();
16         System.out.println("After Deserialize");
17         user.desSelf();
18     }
复制代码

     在5、6两行设置了age为25,name为Tom,然后输出了UserInfo自己的描述:

Before Serialize
Default Postcode: 310000
Age: 25
Name: Tom

     可以看到Age和Name分别是设置的值。defaultPostCode是UserInfo的一个静态变量,它的值是类中指定的310000。然后将这个对象进行了序列化,保存在temp.out中。

     在第10行修改了defaultPostcode的值为110,然后反序列化并输出user的描述信息,结果如下:

After Deserialize
Default Postcode: 110
Age: 25
Name: Tom

     为什么反序列化后defaultPostcode不是310000而是修改的110呢?因为序列化保存的是对象的状态,而静态变量属于类的状态,在序列化的时候不会被保存。

     注意,需要被序列化的对象必须实现Serializable接口,否则在序列化的时候会抛出java.io.NotSerializableException异常。

     实现Serializable接口总是会要求添加一个serialVersionUID属性,有以下两种形式:

  private static final long serialVersionUID = 5511561554099546149L;
  private static final long serialVersionUID = 1L;

     它们有什么区别呢?一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。那么随机生成的序列化 ID 有什么作用呢,有些时候,通过改变序列化 ID 可以用来限制某些用户的使用。

     下面看一个和序列化相关的关键字Transient(在《ArrayList源码分析》中提到过)。

      Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。

      transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。

    有点抽象,看个例子应该能明白。

复制代码
 1 public class UserInfo implements Serializable {
 2      private static final long serialVersionUID = 996890129747019948L;
 3      private String name;
 4      private transient String psw;
 5  
 6      public UserInfo(String name, String psw) {
 7          this.name = name;
 8          this.psw = psw;
 9      }
10  
11      public String toString() {
12          return "name=" + name + ", psw=" + psw;
13      }
14  }
15  
16 public class TestTransient {
17     public static void main(String[] args) {
18         UserInfo userInfo = new UserInfo("张三", "123456");
19         System.out.println(userInfo);
20         try {
21             // 序列化,被设置为transient的属性没有被序列化
22             ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
23                     "UserInfo.out"));
24             o.writeObject(userInfo);
25             o.close();
26         } catch (Exception e) {
27             // TODO: handle exception
28             e.printStackTrace();
29         }
30         try {
31             // 重新读取内容
32             ObjectInputStream in = new ObjectInputStream(new FileInputStream(
33                     "UserInfo.out"));
34             UserInfo readUserInfo = (UserInfo) in.readObject();
35             //读取后psw的内容为null
36             System.out.println(readUserInfo.toString());
37         } catch (Exception e) {
38             // TODO: handle exception
39             e.printStackTrace();
40         }
41     }
42 }
复制代码

     下面说一下上文提到的ArrayList中的writeObject和readObject。先看这两个方法在ArrayList中的具体内容。

复制代码
 1 private void writeObject(java.io.ObjectOutputStream s)
 2         throws java.io.IOException{
 3     int expectedModCount = modCount;
 4     s.defaultWriteObject();
 5     s.writeInt(elementData.length);
 6     for (int i=0; i<size; i++)
 7         s.writeObject(elementData[i]);
 8 
 9     if (modCount != expectedModCount) {
10         throw new ConcurrentModificationException();
11     }
12 }
13 
14 private void readObject(java.io.ObjectInputStream s)
15         throws java.io.IOException, ClassNotFoundException {
16     s.defaultReadObject();
17     int arrayLength = s.readInt();
18     Object[] a = elementData = new Object[arrayLength];
19     for (int i=0; i<size; i++)
20         a[i] = s.readObject();
21 }
复制代码

     这两个方法都是private的且没在ArrayList中被调用过,那为什么需要这两个方法呢?

     writeObject和readObject并不是在每个类和接口中都会定义,而只是定义在哪些在序列化和反序列化过程中需要特殊处理的类中。

  stackoverflow上的解答:http://stackoverflow.com/questions/7467313/why-are-readobject-and-writeobject-private-and-why-would-i-write-transient-vari

     也就是说通过这两个方法可以自己去控制序列化和反序列化的过程。下面是这两个方法的一个例子。

复制代码
 1 private static final long serialVersionUID = 1L;
 2 
 3     private String password = "pass";
 4 
 5     public String getPassword() {
 6         return password;
 7     }
 8 
 9     public void setPassword(String password) {
10         this.password = password;
11     }
12 
13     private void writeObject(ObjectOutputStream out) {
14         try {
15             PutField putFields = out.putFields();
16             System.out.println("原密码:" + password);
17             password = "encryption";//模拟加密
18             putFields.put("password", password);
19             System.out.println("加密后的密码" + password);
20             out.writeFields();
21         } catch (IOException e) {
22             e.printStackTrace();
23         }
24     }
25 
26     private void readObject(ObjectInputStream in) {
27         try {
28             GetField readFields = in.readFields();
29             Object object = readFields.get("password", "");
30             System.out.println("要解密的字符串:" + object.toString());
31             password = "pass";//模拟解密,需要获得本地的密钥
32         } catch (IOException e) {
33             e.printStackTrace();
34         } catch (ClassNotFoundException e) {
35             e.printStackTrace();
36         }
37 
38     }
39 
40     public static void main(String[] args) {
41         try {
42             ObjectOutputStream out = new ObjectOutputStream(
43                     new FileOutputStream("result.obj"));
44             out.writeObject(new Test());
45             out.close();
46 
47             ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
48                     "result.obj"));
49             Test t = (Test) oin.readObject();
50             System.out.println("解密后的字符串:" + t.getPassword());
51             oin.close();
52         } catch (FileNotFoundException e) {
53             e.printStackTrace();
54         } catch (IOException e) {
55             e.printStackTrace();
56         } catch (ClassNotFoundException e) {
57             e.printStackTrace();
58         }
59     }
复制代码

     writeObject 方法中,对密码进行了加密,在 readObject 中则对 password 进行解密,只有拥有密钥的客户端,才可以正确的解析出密码,确保了数据的安全。

     最后说一下序列化的存储规则。

复制代码
 1 public class Test {
 2     public static void main(String[] args) throws IOException,
 3             ClassNotFoundException {
 4         FileOutputStream fos = new FileOutputStream("temp.out");
 5         ObjectOutputStream oos = new ObjectOutputStream(fos);
 6         UserInfo user = new UserInfo();
 7         user.setAge(25);
 8         user.setName("Tom");
 9         oos.writeObject(user);
10         oos.flush();
11         System.out.println(new File("temp.out").length());
12         oos.writeObject(user);
13         oos.flush();
14         oos.close();
15         System.out.println(new File("temp.out").length());
16 
17         FileInputStream fis = new FileInputStream("temp.out");
18         ObjectInputStream ois = new ObjectInputStream(fis);
19         UserInfo user1 = (UserInfo) ois.readObject();
20         UserInfo user2 = (UserInfo) ois.readObject();
21         ois.close();
22         System.out.println(user1 == user2);
23     }
24 }
复制代码

     为什么同一对象写入两次,文件的大小不是写入一次的文件大小的两倍呢?而第三次写入和第二次写入增加的长度是一样的呢?为什么反序列化后的两个对象比较结果是true呢?

     Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,上面增加的 5 字节的存储空间就是新增引用和一些控制信息的空间。反序列化时,恢复引用关系,使得user1和user2二者相等,输出 true。该存储规则极大的节省了存储空间。

     肯定还有我不知道的内容,望多交流讨论。 

原文出处:http://www.hello-code.com

【java】java序列化、ArrayList序列化、序列化策略 1、如果一个类想被序列化,需要实现Serializable接口。否则将抛出异常,这是因为,在序列化操作过程中会对类型进行检查,要求被序列化的类必须属于Enum、Array和Serializable类型其中的任何一种。2、在变量声明前加上该关键字,可以阻止该变量被序列化到文件中。3、在类中增加writeObject 和 readObject 方法可以实现自定义序列化策略。 阅读详情

相关推荐

微带天线理论学习笔记(1)

微带天线的概念是由Deschamps于1953年提出来的,它是在一块厚度远小于工作波长的介质基片的一面敷以金属辐射片、一面全部敷以金属薄层作接地板而成。辐射片可以根据不同的要求设计成各种形状。微带天线具有质量轻、体积小和易于制造等优点,广泛应用于个人无线通信中。

qq_36521926的博客 6227

java 序列化的学习总结

学习java 序列化时做的总结学习

qq_53844452的博客 246

别再只盯着ADC了!手把手教你拆解HLW8032模块的隔离与非隔离采样电路(附BOM清单)

本文深入解析HLW8032模块的隔离与非隔离采样电路设计,提供工程化决策指南。从安全间距到PCB布局,再到误差分析和BOM清单优化,手把手教你避开常见陷阱,确保产品级设计的可靠性和精度。附实用校准策略和关键元器件选型建议,助力硬件开发者提升设计水平。

weixin_29206669的博客 402

Java 序列化详解

Java 序列化(Serialization)是指将一个 Java 对象转换成字节序列,以便在网络上传输或存储在本地磁盘中。而反序列化(Deserialization)则是将已经序列化的字节序列恢复为 Java 对象。Java 提供了自带的序列化机制,可以通过实现 Serializable 接口以及使用 ObjectOutputStream 和 ObjectInputStream 类来实现序列化和反序列化。

兴趣是最好的老师,勤能补拙 3095

基于FPGA的工业相机项目大赏1——cmos线阵相机

●CMOS CL0402 作为图像传感芯片,曝光后产生一定格式的图像数据;●FPGA ZYNQ7020 作为主控芯片负责cmos驱动控制、图像像素的采集、cmos寄存器的配置、cameralink协议的实现、上位机串口通信的实现;●Cameralink端子实现图像数据的高速串行发送,将数据传送至采集卡PC端。系统工作流程如下: FPGA 上电加载配置程序,计算机通过异步串口向 FPGA 发送控制信息,FPGA对接收的控制信息进行分析判断。

weixin_41895751的博客 6400

XSS漏洞之PDF生成:从XSS到服务端任意文件读取

XSS是最为常见的Web漏洞之一,多年来连续入选OWASP TOP10,相信大家都耳熟能详。 它是一种代码注入类的攻击,是一种客户端侧的攻击,攻击者通过在Web应用中注入恶意JavaScript代码,通过点击URL,最终在受害者浏览器端执行的一种漏洞。主要有反射型XSS、存储型XSS、基于DOM的XSS三类。XSS一些比较常规的危害大概有:重定向浏览器、窃取Cookie、浏览器劫持等。本文章侧重于发现XSS后的进一步利用。 主要介绍在某次实际测试过程中,发现XSS漏洞之后,如何进一步的利用,最终通过XSS达

计算机毕业论文源码,学生个人网页制作html源码。贴近用户做网络推广和互联网优化。 3780

java序列化总结了几点

1、序列化:将一个对象编码成字节流,反序列化:将字节流编码重构成对象; 2、序列化版本号serialVersionUID: 没有设置这个值的时候,会有一个默认的(根据类名、接口名、成员名来生成),后续如果有变动默认的uid会不同,兼容性会受到影响。InvalidClassException 3、序列化可能够破坏对象内部的约束关系; 4、Date、BigInteger(值类)和集合需要seri...

lhp534的专栏 332

把 OData V4 服务真正发布出去:事务码 /IWFND/V4_ADMIN 在 SAP S/4HANA On-Premise 里的定位与用法

本文介绍了SAP S/4HANA中的事务码/IWFND/V4_ADMIN,这是SAP Gateway管理OData V4服务的关键工具。该事务码主要负责将后端注册的OData V4服务以服务组形式发布到前端,并维护系统别名路由、测试入口和日志跳转。与OData V2不同,V4采用服务组概念以支持跨服务导航,类似商场统一管理多个专柜。文章还通过实际案例说明,未发布服务组会导致BAS等工具无法发现OData V4服务,并提供了验证服务组状态的访问路径和ABAP示例代码。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 207

java之序列化与反序列化

序列化与反序列化的理解

m0_73866527的博客 1683

CVE-2021-22205 GITLAB 未授权 RCE 漏洞

简介 GitLab是由GitLab Inc.开发的一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,可通过Web界面访问公开或私人项目。由于GitLab存在未授权的端点,导致该漏洞在无需进行身份验证的情况下即可进行利用。 漏洞利用 上工具 python3 poc import sys import requests from bs4 import BeautifulSoup requests.packages.urllib3.disable_warnings() def .

qq_32445755的博客 886

损失函数大汇总(三十八)(AUCPR Loss附公式推导与代码)

本文系统介绍了AUCPR Loss的原理与应用。针对不平衡分类任务中AUC指标不够敏感的问题,提出通过优化PR曲线面积(AUCPR)来提升模型性能。文章详细推导了AUCPR的可微近似实现:首先用sigmoid函数软化阈值判断,构造可微的TP/FP/FN计数;然后基于软Precision和Recall计算近似PR曲线面积;最后通过数值积分得到可优化的损失函数。特别讨论了温度参数τ对训练稳定性的影响,并比较了AUCPR与AUC、AP等指标的异同。该方法适用于医学筛查、欺诈检测等极端不平衡场景,能更准确反映模型对

悦学共鸣,温柔以待,汇聚光芒,共同成长 441

Java中的序列化及序列化ID

参考转载自: 秒懂Java序列化与反序列化 Java的序列化ID的作用 1. 定义 Java的序列化:是指把Java对象转换为字节序列的过程 Java的反序列化:是指把字节序列恢复为Java对象的过程 2. 为什么需要 我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。换句话说,一方面,.

三明治文鱼的博客 5841

【11】科曼医疗——科曼医疗 嵌入式--面试,校招,面试问答记录

科曼医疗嵌入式校招面试记录:3位面试官分别考察应用层技术、底层技术和HR面。技术问题涵盖C++特性(多态、虚函数、指针与引用区别)、内存管理(malloc与new对比)、嵌入式基础(51最小系统、IIC/SPI协议)及项目经验(智能黑板擦专利项目)。同时考察了Linux使用经验、STM32开发及嵌入式操作系统认知。最后环节应聘者询问了开发环境及面试流程。面试内容全面覆盖嵌入式开发核心知识点。

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 1251

【Java】Java序列化和反序列化

为了序列化对象,我们调用ObjectOutputStream类的writeObject()方法,而为了反序列化,则调用ObjectInputStream类的readObject()方法。SerializeISA类已序列化扩展了Person类的Student类对象,而Person类是可序列化的。序列化和反序列化过程是平台无关的,这意味着您可以在一个平台上对对象进行序列化,在另一个平台上进行反序列化。现在,id将不会序列化,因此在序列化之后反序列化对象时,您将不会得到id的值。它是序列化的逆操作。

double222222的博客 1142

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

什么是Java序列化,如何实现java序列化

什么是Java序列化,如何实现java序列化 简要解释:  序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。  序列化是为了解决在对对象流进行读写操作时所...

533

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

什么是java序列化,如何实现java序列化?

Java序列化:把Java对象转换为二进制的数据流流。  反序列化就是把字节序列恢复为Java对象的过程。      实现:将需要序化的类实现Serializable接口就可以了,该接口没有任何方法,可以理解为一个标记,即表明这个类可以序列化。注意的是被关键字static、transient修饰的变量不能被序列化。在被序列化后,transient修饰的变量会被设为初始值。如int型的是0、对象型

m_h7769的博客 2396

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

从Java序列化到Hadoop序列化

一个原生的类讲解一下,自定义比较器讲解一下,内部类讲解一下。WritableComparator是 WritableComparables的比较器。这个基础实现类使用是自然的排序规则,如果要使用其他的排序规则,需要重写compare(WritableComparable,WritableComparable)方法。

Jenny19992018的博客 591

java序列化指的是什么,java的序列化是什么

序列化:指堆内存中的java对象数据,通过某种方式把对存储到磁盘文件中,或者传递给其他网络节点(网络传输)。这个过程称为序列化,通常是指将数据结构或对象转化成二进制的过程。 (推荐学习:java课程)即将对象转化为二进制,用于保存,或者网络传输。序列化的作用① 想把内存中的对象保存到一个文件中或者数据库中时候;② 想用套接字在网络上传送对象的时候;③ 想通过RMI传输...

weixin_39820226的博客 2019

Java序列化与反序列化

*序列化(Serialization)**是将对象的状态信息转换为可以存储或传输的形式的过程。在Java中,序列化是将对象转换为字节序列的过程。**反序列化(Deserialization)**是将序列化的字节序列恢复为对象的过程。序列化:对象 → 字节流反序列化:字节流 → 对象通过实现和readObject// 不序列化密码// 自定义序列化// 调用默认序列化// 对密码进行加密后再序列化// 自定义反序列化// 调用默认反序列化// 解密密码。

weixin_74417835的博客 1378

java序列化

含义、意义使用场景 序列化:将对象写入到IO流中 反序列化:从IO流中恢复对象 意义:序列化机制允许将实现序列化的Java对象转换位字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。 使用场景:所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:

栋幺栋幺-的博客 1920
上一篇: jQuery选择器大全
下一篇: 破解.net程序 编译和反编译方法
普通网友
博客等级 码龄14年 0粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值