java对象 序列化_Java基础之对象序列化

1. 什么是Java对象序列化

Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。

使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的"状态",即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。

除了在持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。Java序列化API为处理对象序列化提供了一个标准机制。在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。

2.JDK中序列化的方法

2.1序列化例子

实现java.io.Serializable或Externalizable接口,后者继承前者,声明不用系统默认的序列化方法, 程序员自己编写序列化写读方法。

public classSimpleSerial {public static void main(String[] args) throwsException {

File file= new File("person.out");

ObjectOutputStream oout= new ObjectOutputStream(newFileOutputStream(file));

Person person= new Person("John", 101, Gender.MALE);

oout.writeObject(person);

oout.close();

ObjectInputStream oin= new ObjectInputStream(newFileInputStream(file));

Object newPerson= oin.readObject(); //没有强制转换到Person类型

oin.close();

System.out.println(newPerson);

}

}

当重新读取被保存的Person对象时,并没有调用Person的任何构造器,看起来就像是直接使用字节将Person对象还原出来的。

当Person对象被保存到person.out文件中之后,我们可以在其它地方去读取该文件以还原对象,但必须确保该读取程序的CLASSPATH中包含有Person.class(哪怕在读取Person对象时并没有显示地使用Person类,如上例所示),否则会抛出ClassNotFoundException。

2.2序列化ID问题

虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。如果不指定序列化ID,JAVA会用指纹摘要算法自动为该class生成一个默认ID,在类添加修改字段时,序列化ID自动改变,再反序列化之前的类就会失败,包序列化ID不同的错误,因此必须根据需要指定序列化ID,如果ID不变,则类字段有添加改动等时依然兼容反序列化之前的文件,反之不想兼容之前的,将ID设为不同即可。

2.3Serializable的作用

为什么一个类实现了Serializable接口,它就可以被序列化呢?一般类继承该接口后,才可使用ObjectOutputStream来持久化对象,否则调会报不能序列writeObject0时会化异常,

private void writeObject0(Object obj, boolean unshared) throwsIOException {if (obj instanceofString) {

writeString((String) obj, unshared);

}else if(cl.isArray()) {

writeArray(obj, desc, unshared);

}else if (obj instanceofEnum) {

writeEnum((Enum) obj, desc, unshared);

}else if (obj instanceofSerializable) {

writeOrdinaryObject(obj, desc, unshared);

}else{if(extendedDebugInfo) {throw new NotSerializableException(cl.getName() + "\n"

+debugInfoStack.toString());

}else{throw newNotSerializableException(cl.getName());

}

}

}

从上述代码可知,如果被写对象的类型是String,或数组,或Enum,或Serializable,那么就可以对该对象进行序列化,否则将抛出NotSerializableException。

如果仅仅只是让某个类实现Serializable接口,而没有其它任何处理的话,则就是使用默认序列化机制。使用默认机制,在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。所以,如果一个对象包含的成员变量是容器类对象,而这些容器所含有的元素也是容器类对象,那么这个序列化的过程就会较复杂,开销也较大。

2.4影响序列化的方法

在现实应用中,有些时候不能使用默认序列化机制。比如,希望在序列化过程中忽略掉敏感数据,或者简化序列化过程。

(1)transient关键字

当某个字段被声明为transient后,默认序列化机制就会忽略该字段。此处将Person类中的age字段声明为transient

(2)writeObject()方法与readObject()方法

对于上述已被声明为transitive的字段age,除了将transitive关键字去掉之外,是否还有其它方法能使它再次可被序列化?方法之一就是在Person类中添加两个方法:writeObject()与readObject(),如下所示:

public class Person implementsSerializable {transient private Integer age = null;private void writeObject(ObjectOutputStream out) throwsIOException {

out.defaultWriteObject();

out.writeInt(age);

}private void readObject(ObjectInputStream in) throwsIOException, ClassNotFoundException {

in.defaultReadObject();

age=in.readInt();

}

}

在writeObject()方法中会先调用ObjectOutputStream中的defaultWriteObject()方法,该方法会执行默认的序列化机制,此时会忽略掉age字段。然后再调用writeInt()方法显示地将age字段写入到ObjectOutputStream中。readObject()的作用则是针对对象的读取,其原理与writeObject()方法相同。必须注意地是,writeObject()与readObject()都是private方法,被ObjectOutputStream中的writeSerialData方法,以及ObjectInputStream中的readSerialData用反射调用。

(3)Externalizable接口

无论是使用transient关键字,还是使用writeObject()和readObject()方法,其实都是基于Serializable接口的序列化。JDK中提供了另一个序列化接口--Externalizable,使用该接口之后,之前基于Serializable接口的序列化机制就将失效。使用Externalizable进行序列化,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。因此实现Externalizable接口的类必须要提供一个无参的构造器,且它的访问权限为public。然后被序列化对象重载writeExternal()与readExternal()方法实现序列化反序列化操作。

public class Person implementsExternalizable {private String name = null;transient private Integer age = null;

……

@Overridepublic void writeExternal(ObjectOutput out) throwsIOException {

out.writeObject(name);

out.writeInt(age);

}

@Overridepublic void readExternal(ObjectInput in) throwsIOException, ClassNotFoundException {

name=(String) in.readObject();

age=in.readInt();

}

}

(4)readResolve()方法

当我们使用Singleton模式时,应该是期望某个类的实例应该是唯一的,但如果该类是可序列化的,为了能在序列化过程仍能保持单例的特性,可以在Person类中添加一个readResolve()方法,在该方法中直接返回单例对象。无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象,而被创建的对象则会被垃圾回收掉。

public class Person implementsSerializable {private static classInstanceHolder {private static final Person instatnce = new Person("John", 31, Gender.MALE);

}public staticPerson getInstance() {returnInstanceHolder.instatnce;

}

……private Object readResolve() throwsObjectStreamException {returnInstanceHolder.instatnce;

}

}

3、注意事项

a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

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

c)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:

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

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

把一个对象完全转成字节序列,方便传输。

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

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

相关文章

NET问答: 到底是返回 null 好,还是 空集合 好?

咨询区 Omu:我是一个 C# 菜鸟,说实话,这个问题是一个非常困惑于我们这样初学者的一个问题,我想知道实际开发中的 最佳实践 应该是什么样的?回答区 user1228:如果要我选的话,我会用 空集合&#…

人工智能读心术

全世界只有3.14 % 的人关注了数据与算法之美对于许多无法发出声音的人来说,他们想说的话会通过某种信号隐藏在大脑中。人类无法直接破译这些信号。但是,最近有三个研究小组在“破译”这种大脑语言密码上取得了一定进展。Science杂志最新报道了哥伦比亚大…

非彼拉且数列的实现

递归算法实现&#xff1a; public static int F(int n) {if(n0 || n1){return 1;}else{return F(n-1)F(n-2)}} 迭代算法实现&#xff1a; public static int Fx(int n ) {int i 1;int j 1;int temp 0;if(n 0 || n1){return 1;}for(int k 2; k<n; k){temp i j;i j;j…

今日港股期货(港股期货今日交易动向)

港股期货收涨0.6% 首次突破31000点 今日港股期货大涨&#xff0c;形势一时看好。其中&#xff0c;恒生指数期货一度突破31000点关口&#xff0c;创出历史新高。分析人士表示&#xff0c;市场情绪积极&#xff0c;投资者对于全球经济复苏前景和中国经济增长的预期不断提高&…

春节特惠活动┃一张纸一幅图,竟然提高了10倍的学习和工作效率!?

▲数据汪特别推荐点击上图进入玩酷屋人类大脑的容量远远超出一般人的想象&#xff0c;时到21世纪的今天&#xff0c;我们对大脑的运用远远不够。大脑机能的使用率基于我们的思维模式&#xff0c;而思维导图正是开发大脑中最有效的利器&#xff01;之前小木给大家推荐了一套基于…

java class文件 代码_java_基础——用代码编译.java文件+加载class文件

java_基础——用代码编译.java文件加载class文件java_基础——用代码编译.java文件加载class文件【简单编译的流程】package com.zjm.www.test;import java.io.IOException;import javax.tools.JavaCompiler;import javax.tools.JavaCompiler.CompilationTask;import javax.too…

WPF 记一个Popup踩坑记录

看名字就知道&#xff0c;它是一个弹出控件&#xff0c;顾名思义&#xff0c;我们可以用它来实现类似Combobox那种&#xff0c;点击后弹出下面选项列表的操作。记录&#xff1a;需求&#xff1a;有一个文本框 &#xff0c;鼠标点击后&#xff0c;弹出一个Popup。我编写了以下xa…

通过电话号码获取姓名 (+86或者飞信)

2019独角兽企业重金招聘Python工程师标准>>> /** * 通过电话号码获取姓名 (86或者飞信) */ /* public String getContactName(String phoneNum) { String contactName "";// 处理电话号码格式问题 if (phoneNum.length() > 11) {ContentResolver cr …

春节特惠活动┃强烈推荐!孩子的科普从这套全球畅销250万册的最酷科学书起步...

▲数据汪特别推荐点击上图进入玩酷屋在马斯的学生时代的记忆中&#xff0c;数学定义定理、化学方程式、物理公式……这些科学知识点总是冷冰冰的&#xff0c;枯燥、深奥也总是科学的代名词。如今教育局明确规定科学课是小学必修课&#xff0c;孩子也逐步接受科学知识的熏陶。但…

删除未使用的引用 | Visual Studio 2019(16.10)新功能试用

当解决方案很小时&#xff0c;我们清楚地知道解决方案中使用了哪些项目引用和NuGet包&#xff0c;要想清理它们很容易。而对于大型的解决方案&#xff0c;有哪些包在使用中&#xff0c;开发人员很难找到它们&#xff0c;或者找起来可能很耗时。Visual Studio 2019(16.10)添加了…

解决iPhone网络软件在睡眠情况断线问题

如果你希望使用iPhone的网络功能并保持长连接&#xff0c;并使用Wifi的话&#xff0c;你可能会发现一个问题&#xff0c;那就是在iPhone处于睡眠状态时&#xff0c;Wifi会中断&#xff0c;这样程序就无法保持连接。&#xff08;iPhone非官方SDK&#xff09; 下面的代码可能会帮…

java jli.dll_JVM、JRE、JDK之间的区别和联系,你居然还不知道?

JDK包含了JRE,JRE包含了JVMJDK:java开发工具包,针对java开发人员,可以编译运行java程序JRE:java运行时环境,针对使用java程序的客户,可以运行字节码(.class),但是不能编译Java源码JVM:用来解释执行字节码文件(.class),但不能正确的执行什么是JVMJVM是JRE的一部分,是虚拟出来的一…

女生转行IT与男生有什么不一样?

全世界只有3.14 % 的人关注了数据与算法之美在我的后台咨询者当中&#xff0c;女生向我咨询最多的问题就是&#xff1a;女生转行IT有什么困难&#xff1f;是不是很多IT企业都不要女生啊&#xff1f;女生的逻辑不如男生&#xff0c;是不是学不好编程&#xff1f;等等。1以上的所…

Blazor 基础入门

Blazor 基础知识IntroBlazor 是微软在 .NET 里推出的一个 WEB 客户端 UI 交互的框架&#xff0c;使用 Blazor 你可以代替 JavaScript 来实现自己的页面交互逻辑&#xff0c;可以很大程度上进行 C# 代码的复用&#xff0c;Blazor 对于 .NET 开发人员来说是一个不错的选择。托管模…

关于MySQL 查询表数据大小的总结

关于MySQL 查询表数据大小的总结 一&#xff1a;关于mysql表数据大小我们知道mysql存储数据文件一般使用表空间存储 当mysql使用innodb存储引擎的时候&#xff0c; mysql使用表存储数据分为共享表空间和独享表空间两种方式 共享表空间&#xff1a;Innodb的所有数据保存在一个单…

java 列表展开方式_android列表控件实现展开、收缩功能

最近在做一个Rss阅读器&#xff0c;我看了一看别人做的阅读器中的lisView可以伸缩&#xff0c;展开&#xff0c;我就在网上搜索了一下。果然让我找到&#xff0c;下面就我找到的一个小例子&#xff0c;给大家分享一下。ActivityMain .javapackage com.android;import android.a…

每个人都应该学习编程,因为它会教你如何思考

▲数据汪特别推荐点击上图进入玩酷屋扎克伯格11岁开始学习编程&#xff0c;创办Facebook&#xff1b;比尔盖茨13岁学习编程&#xff0c;创办微软……乔布斯说&#xff1a;“每一个人都应该学习电脑编程&#xff0c;因为它会教你如何思考。"现在在北京上海&#xff0c;顶级…

.NET Core HttpClient请求异常思考

【导读】上一篇我们讨论了针对项目上异常信息的具体分析而给出对应解决方案&#xff0c;本篇仅是我个人对相关异常信息了解过后的进一步学习和思考&#xff0c;希望对后续遇到此异常信息的同学们给予思路扩展下面我们结合如下两个异常信息进行大致排查分析&#xff0c;到底什么…

Ubuntu 12.10 安装官方JDK

安装官方JDK前先删除系统自带的OpenJDK sudo apt-get purge openjdk* 一、下载官方JDK http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html 下载后的文件叫做&#xff1a;jdk-7u10-linux-i586.tar.gz 二、安装JDK 进入下载的文件目录&#…

程序员编程10大原则,请牢牢记住!

全世界只有3.14 % 的人关注了数据与算法之美1、想清楚&#xff0c;再动手写代码刚入行的新手&#xff0c;为了展示自己的能力&#xff0c;拿到需求迫不及待地就开始上手写代码&#xff0c;大忌&#xff01;2、不交流&#xff0c;就会头破血流不爱说话和沟通&#xff0c;需求都理…