java对象的序列化机制详解

Java对象的序列化机制

  Java对象的序列化,是将内存中的java对象转化为二进制的字节流,然后保存到磁盘中或者在网络上。这就是序列化对象,反序列化顾名思义就是将对象的二进制字节流恢复成原来的对象。注意只有对象的类名和属性能被序列化(包括基本类型,数组,对其他对象的引用)不包括方法,static属性(静态属性)transient属性(瞬态属性)都不会被序列化。

  那什么叫做序列化的对象呢,在Java中不是所有类都是序列化类,如果一个类要实现序列化就必须实现下面两个接口之一:

   (1)Serializable接口  (2)Externalizable接口

对于这两个接口的区别后面就会知道的,我们先把类都实现Serializable接口,这个接口java没有提供任何的方法,java设计他只是作为一个类的序列化的标志,表明此类可以进行序列化。

  如果要讲java对象转化为二进制的字节流并写出,就一定需要对象的流来进行输出,所以这里用到ObjectOutputStream类,这个输出流是一个处理流,所以需要创建一个字节输出流然后用这个处理流进行包装,所以处理流也叫作包装流。反之ObjectInputSteam是将对象写入的类。写出的对象方法是ObjectOutputStem对象.writeObject(序列化对象的实例)。写入的方法是ObjectInputStream的对象.readObject(序列化的对象);说了这么多,我就做一个例子吧。。

  代码:创建一个实现序列化的Person

 

public class Person implements Externalizable {private String name;private  int age;public Person1(String name,int age) {this.name=name;this.age=age;//这个地方用于测试序列化和反序列化对象时候实例化类的情况System.out.println("带参数的构造器的使用");}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}

 

代码:创建测试类,进行测试

public static void main(String[] args) throws IOException {//如果处理流,当关闭流的时候就不需要再将节点流进行关闭了//这是对对象进行写出的操作(序列化对象)FileOutputStream fos=null;ObjectOutputStream oos=null;try {fos=new FileOutputStream(new File("E://javatest.txt"));oos=new ObjectOutputStream(fos);Person per=new Person("孙悟空",66);oos.writeObject(per);} catch (FileNotFoundException e) {// TODO Auto-generated catch block
            e.printStackTrace();}finally {if(oos!=null) {oos.close();}}//这是对对象进行写入的操作(反序列化对象)FileInputStream fis=null;ObjectInputStream ois=null;try {fis=new FileInputStream("E://javatest.txt");ois=new ObjectInputStream(fis);//处理流将文件的字节流进行包装//将对象反序列化写入的时候得到的都是Object类型的数据,必须进行强制类型的转化Person per=(Person)ois.readObject();System.out.println("姓名"+per.getName()+"年龄"+per.getAge());} catch (Exception e) {e.printStackTrace();} finally {if(ois!=null) {ois.close();}}}

readObject方法会抛出ClassNotFoundException异常,也就是说当反序列化时候找不到对应的java类会将引发这个异常,因为反序列化读取的仅仅是java对象的数据,而不是java类,因此采用反序列化恢复java对象时,必须提供该java对象所属类的class文件,否则就会引发该异常。

  输出结果可以看出当反序列化的时候构造器没有执行,也就是反序列化类无需通过构造器来进行初始化java对象

 注:如果我们向文件中使用序列化机制写入多个java的对象,使用反序列化机制恢复对象时必须按实际的写入顺序读取。 

   Y(^o^)Y属性是引用类型的对象的序列化

   我们上面所说的属性都是String类型和基本类型,如果我们需要一个引用类型呢,那么这个引用类型也必须是可序列化的类,否则拥有该类型的属性类不可序列化。下面我将要定义一个引用类型的属性,重新创建一个Teacher类,引用属性必须实现序列化,否则Treacher不论实现不实现(1)Serializable接口  (2)Externalizable接口这两个接口,他都不是序列化的类,因为当对象序列化的时候,会顺带着把引用类型的属性进行序列化,所以要想Teacher是序列化的类,则必须将Person的类进行序列化。

  代码Teacher

 

public class Teacher implements Serializable {private String name;private Person student;//引用类型的属性(这个Person类就是上面实现序列化的类)public Teacher(String name,Person student) {this.name=name;this.student=student;System.out.println("带参数的构造器的使用");}public String getName() {return name;}public void setName(String name) {this.name = name;}public Person getStudent() {return student;}public void setStudent(Person student) {this.student = student;}
}

 

代码 测试代码

public static void main(String[] args) throws IOException {// TODO Auto-generated method stub
FileOutputStream fos=null;ObjectOutputStream oos=null;Person p=new Person("孙悟空",66);Teacher t1=new Teacher("玄奘法师",p);Teacher t2=new Teacher("菩提祖师",p);try {fos=new FileOutputStream(new File("E://javatext.txt"));oos=new ObjectOutputStream(fos);oos.writeObject(t1);oos.writeObject(t2);oos.writeObject(p);oos.writeObject(t1);} catch (FileNotFoundException e) {// TODO Auto-generated catch block
            e.printStackTrace();} finally {if(oos!=null) {oos.close();}}}
}

分析这段代码可以看出我创建出来了三个类。Person p=new Person("孙悟空",66);Teacher t1=new Teacher("玄奘法师",p);Teacher t2=new Teacher("菩提祖师",p);如果我将这三个类进行对象的序列化的话,t1写出并且Person类也会进行序列化,同理t2也是,然后我们又显示序列化了Person类,所以Person类在此次写出中,被序列化了三回,那么对于t1,t2来说实际上他们的Person类是同一个,但是如果Person序列化三回的话,t1,t2就没有引用同一个Person类,这显然是不符合实际情况的。Java对此采用了一种特殊的序列化算法,算法的内容是:

(1)所有保存到磁盘中的对象都有一个序列化编号。

(2)当程序师徒序列化一个对象的时候,程序将先检查对象是否已经序列化过,只有当该对象从未(在本次虚拟机中)被序列化过,系统才会将该对象转化成字节序列并输出。

(3)如果某个对象是已经序列化过的,程序将直接只是输出一个序列化编号,而不是重新序列化该对象。

Y(^o^)Y序列化的对象是可变的类

  根据java的序列化机制,当我先写进去序列化的时候,如果我改变了可变类的属性值,那么当我想再次进行序列化的时候就不能把更改后的值序列化了,因为java的序列化机制当在此序列化同一的对象的时候,输出的是一个序列化编号。程序会比较两个对象是同一个对象,就不会把对象重新的序列化。就是更改后的对象并没有被写入。这再次验证了java的序列化机制。

  代码 测试类

public class VolatileClassTest {/*** 序列化可变类* @param args* @throws IOException * @throws ClassNotFoundException */public static void main(String[] args) throws IOException, ClassNotFoundException {// TODO Auto-generated method stub
FileOutputStream fos=null;ObjectOutputStream oos=null;FileInputStream fis=null;ObjectInputStream ois=null;try {//进行序列化的操作fos=new FileOutputStream(new File("E://javatest.txt"));oos=new ObjectOutputStream(fos);Person p=new Person("孙悟空",600);oos.writeObject(p);//将对象进行序列化p.setName("红孩儿");//可变类将姓名属性设置为红孩儿,可变类oos.writeObject(p);//将更改后的类进行序列化//进行反序列化操作fis=new FileInputStream(new File("E://javatest.txt"));ois=new ObjectInputStream(fis);Person per=(Person)ois.readObject();//输出的姓名还是孙悟空,再次验证了java的序列化机制System.out.println("姓名是"+per.getName());} catch (FileNotFoundException e) {// TODO Auto-generated catch block
            e.printStackTrace();} finally {if(oos!=null) {oos.close();}if(ois!=null) {ois.close();}}}
}

 

转载于:https://www.cnblogs.com/dukc/p/4823710.html

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

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

相关文章

测试并发应用

本文是我们学院课程中名为Java Concurrency Essentials的一部分 。 在本课程中,您将深入探讨并发的魔力。 将向您介绍并发和并发代码的基础知识,并学习诸如原子性,同步和线程安全之类的概念。 在这里查看 ! 目录 1.简介 2. Sim…

无忧企业系统的getshell

方法一:数据库备份 写入后进行数据库备份 路径 shell工具连接 方法二:修改允许上传后缀,直接上传马

如何使用FinalShell、FileZilla上传网站代码到服务器?这两个都是神器

这段时间想做一个导航网站来着,然后就简单写了一个网页,买了一个域名、一台ECS服务器,都是比较便宜的那种,https://www.aliyun.com/minisite/goods?userCode=1k1odmgm 这个学生或者新用户基本都是一折,还能玩得起。所有软件的安装除了选择安装路径,都可以无脑按安装。 …

[CareerCup] 9.6 Generate Parentheses 生成括号

9.6 Implement an algorithm to print all valid (e.g., properly opened and closed) combinations of n-pairs of parentheses.EXAMPLEInput: 3Output: ((())), (()()), (())(), ()(()), ()()() LeetCode上的原题,请参见我之前的博客Generate Parentheses 生成括号…

神经网络:深度学习优化方法

1.有哪些方法能提升CNN模型的泛化能力 采集更多数据:数据决定算法的上限。 优化数据分布:数据类别均衡。 选用合适的目标函数。 设计合适的网络结构。 数据增强。 权值正则化。 使用合适的优化器等。 2.BN层面试高频问题大汇总 BN层解决了什么问…

PDF.js如何添加放大缩小的功能,转换成图片应该如何实现?

把官方的安装包搞下来,自己的PDF文件及index.html添加进去,上面的目录结构是未添加的,我先把PDF文件搞成canvas然后搞成图片,然后再图片上添加按钮对图片进行放大缩小操作,方便对用户行为进行录屏。 <!DOCTYPE HTML> <html data-dpr="1" style="…

mimikatz免杀过360和火绒

mimikatz mimikatz是一款能够从Windows认证&#xff08;LSASS&#xff09;的进程中获取内存&#xff0c;并且获取名闻密码和NTLM哈希值的工具&#xff0c;攻击者可以利用这种功能漫游内网。也可以通过明文密码或者hash值进行提权。这款工具机器出名所以被查杀的几率极高。 1、…

ibatis Parameter index out of range (1 number of parameters, which is 0)

这个错误除了网上常见的like写错之外&#xff0c;这里列出其中一种写法like concat(%, #keyword#, %),还有另外的多写单引号什么的以外&#xff0c;今天遇到另一个原因,百度谷歌各种查也没查到&#xff0c;最后才意识到由于我是在navicat中的写好的再粘贴上去的&#xff0c;注释…

SVN:请求不到主机,应该如何解决?

连了公司的局域网&#xff0c;可能一个账号人多的缘故&#xff0c;给你们讲一下思路。确保一点在同一个局域网。 然后ping一下域名。也是不通的 把域名换成IP进行访问试试&#xff0c;这个检查一下路径没有问题即可。

MSSQL提权

之前对MSSQL提权了解较少&#xff0c;所以在这里记录一些关于这类提权的几种姿势 1.xp_cmdshell提权 存储过程为数据库提供了强大的功能&#xff0c;其类似UDF&#xff0c;在MSSQL中xp_cmdshell可谓臭名昭著了。MSSQL强大的存储过程也为黑客提供了遍历&#xff0c;在相应的权…

如何以及为什么序列化Lambda

总览 lambda序列化在许多用例中很有用&#xff0c;例如持久配置或作为远程资源的访客模式 。 远程访客 例如&#xff0c;因此我想访问远程Map上的资源&#xff0c;可以使用get / put&#xff0c;但是说我只想从Map的值中返回一个字段&#xff0c;我可以将lambda作为访问者来传…

NSTimer注意内存泄露(真该死)

NSTimer可以用来执行一些定时任务&#xff0c;比较常用的方法就是&#xff1a; (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo; 可是&#xff0c;仔细看官方文档中对于参数t…

Redis漏洞利用的4种方法

Redis简介 redis是一个key-value存储系统。和Memcached类似&#xff0c;它支持存储的value类型相对更多&#xff0c;包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash&#xff08;哈希类型&#xff09;。这些数据类型都支持push/pop、add/remov…

系统已有MYSQL环境,如何安装宝塔面板

最近一直想搞一个在线博客网站&#xff0c;把代码部署到服务器。 下载己经下载了宝塔的.exe文件,安装提示系统已经存在MYSQL环境&#xff0c;请用纯净系统安装。 因为我以前做java的&#xff0c;已经装了&#xff0c;现在把它卸载即可。 WINR打开注册表输入regedit。 删除HK…

Mysql命令alter add:增加表的字段

alter add命令用来增加表的字段。alter add命令格式&#xff1a;alter table 表名 add字段 类型 其他;例如&#xff0c;在表MyClass中添加了一个字段passtest&#xff0c;类型为int(4)&#xff0c;默认值为0&#xff1a; mysql> alter table MyClass add passtest int(4) …

宝塔命令号操作全-最实用的莫过于修改密码啦

连续输入五次密码错误&#xff0c;只能CMD进行操作啦。看上图。

swaks使用教程

Swaks基本用法&#xff1a; 1、swaks --to testqq.com 测试邮箱的连通性&#xff1b; 2、参数说明&#xff08;这里只是简单的罗列了一些&#xff0c;至于更加具体的内容可以使用–help进行查看了解&#xff09;&#xff1a; --from testqq.com //发件人邮箱&#xff1…

具有Rx-Java的Couchbase Java SDK

关于Couchbase Java SDK的一件整洁的事情是&#xff0c;它建立在出色的Rx-Java库的基础上&#xff0c;这为与Couchbase服务器实例进行交互提供了一种反应性的方式&#xff0c;一旦掌握了它&#xff0c;它就非常直观。 考虑一个我打算存储在Couchbase中的非常简单的json文档&am…

电脑win7支持的node.js版本

从官网看了都是最新的版本,我这电脑是win7的,最新版支持最低版本win8.1. 只能找一个支持win7、的node版本。 官网:https://nodejs.org/en/download/ 历史版本:https://nodejs.org/en/download/releases/ 建议打开图标下载,打开链接下载速度特别慢。 下载完成后直接傻瓜式安…

in-place数据交换

实现in-place的数据交换 声明&#xff1a;引用请注明出处http://blog.csdn.net/lg1259156776/ 经典的排序问题 问题描述 一个数组中包含两个已经排好序的子数组&#xff0c;设计一个in-place&#xff08;原位操作&#xff09;算法来对这个数组排序。测试数据为 a[] 1 4 5 7 8 …