java基础知识回顾之javaIO类--java序列化和反序列化
/**
*
* 一:理解序列化反序列化及其应用
* 序列化:把堆内存的对象转化成字节流的过程。
* 反序列化:把字节流序列恢复重构成对象的过程。
* 对象的序列化的用途:1.把对象的字节序列持久化,保存到硬盘上,通常是文件当中。
* 2.将对象变成字节流在网络上传输
* 在很多应用当中,需要对某些对象进行序列化,让他们离开堆内存空间,持久化到硬盘上,以便长期保存。
* 比如最常见的web服务器中的Session对象,当有10万个用户并发访问,就有可能出现10万个Session对象,
* 内存吃不消,于是web容器就会把一些Session对象序列化到硬盘上,等要用了在把硬盘中字节序列读到内存中。
* 而不需要重新创建对象。
*
* 再比如,分布式系统在进行网络传输,当两个进程在进行远程通信的时候,在网络上彼此可以发送
* 各种类型的数据,无论是何种类型的数据都会以二进制的形式在网络上传输。这就用到序列化,将java对象转化成字节序列
* ,才能在网络上传送,接受方可以把字节序列在恢复为java对象
*
* 二、JDK类库中的序列化API
*
java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。
对象序列化包括如下步骤:
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。
对象反序列化的步骤如下:
1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法读取对象。
*
*/
import java.io.Serializable;
public class Person1 implements Serializable{
/**
* Serializable:用于给被序列化的类加入ID号,用于判断类和对象是否是同一个版本号
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Person1(String name, int age) {
super();
this.name = name;
this.age = age;
}
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 class ObjectStreamDemo {
/**
* @param args
* @throws IOException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws IOException, ClassNotFoundException {
writeObj();//对象序列化
readObj();//反序列化
}
/**
* 反序列化
* @throws IOException
* @throws ClassNotFoundException
* 对象的反序列化,Person.class文件和obj.object才能实现反序列化
*/
public static void readObj() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("lp.object"));
//对象的反序列化。
Person1 p = (Person1)ois.readObject();
Person1 p1 = (Person1)ois.readObject();
System.out.println(p.getName()+":"+p.getAge());
System.out.println(p1.getName()+":"+p1.getAge());
ois.close();
}
/**
* 持久化对象到文件上,如果对象没有实现Serializable接口,就不能被序列化
* 把堆内存的对象生命周期延长,存放到硬盘上进行持久化,不需要解析,下次我们需要对象,不需要new,直接从硬盘上读重构对象
* @throws IOException
* @throws IOException
*/
public static void writeObj() throws IOException, IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("lp.object"));
//对象序列化。 被序列化的对象必须实现Serializable接口。
oos.writeObject(new Person1("小强",30));
oos.writeObject(new Person1("lp",40));
oos.close();
}
}
输出结果为:小强:30
lp:40

序列化后在项下面生成了lp.object文件,而反序列化是读取lp.object文件重构了对象。
serialVersionUID的作用:是用于给被序列化的类加入ID号,用于判断类和对象是否是同一个版本号。
假设我们一开始没有在Person类中没有添加这个版本号,系统默认的序列化运行时会根据类名,接口名,属性名,方法名等等(该类的各个方面)生成一个默认的serialVersionUID序列化版本号来唯一标识此类。加入我们没有加入serialVersionUID,代码如下:
public class Person1 implements Serializable/*标记接口*/ {
private String name;
private int age;
public Person1(String name, int age) {
super();
this.name = name;
this.age = age;
}
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;
}
}
我们调用上面的代码中writeObj()方法,对要序列化的对象进行序列化,然后调用readObj()反序列化,输出结果为:
小强:30
lp:40
好的,我们在对Person类做一个小小的修改,把private int age的名字变为public int age,其它的都不改变。调用readObj()反序列化,发现,程序报错了:
Exception in thread "main" java.io.InvalidClassException: 无效的类错误
com.lp.io.p2.bean.Person1; local class incompatible: stream classdesc serialVersionUID = -4619097973205016437, local class serialVersionUID = -7230327405276836859
出现了两个serialVersionUID 序列号,而且不一样,我们只修改了那么一点,为什么反序列化会报错呢?
通过看API发现,默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器的不同可能会千差万别,即使我们在要序列化的类中多加一个空格可能导致serialVersionUID版本号截然不同,编译器会重新生成一个版本号。由于序列版本号是标识序列化类的ID,由于修改前和修改后生成的序列化ID不同,所以java虚拟机认为加载的class有问题,所以报类无效的错误。所以当要改动要序列化的类的时候,最好显示的申明serialVersionUID值,这样当你对这个Person类有小小的改动的时候,只要serialVersionUID值没有改变,就不会抛出以上的异常。
最后总结:要序列化的类必须实现Serializable接口,只有实现了这个接口才能被序列化,反序列化。在序列化的类中最好显示的申明serialVersionUID值。
java基础知识回顾之javaIO类--java序列化和反序列化的更多相关文章
- java基础知识回顾之javaIO类---FileWriter和FileReader
FileWriter类的构造方法定义如下: 1.public FileWriter(File file)throws IOException 字符流的操作比字节流操作好在一点,就是可以直接输出字符串了 ...
- java基础知识回顾之javaIO类--RandomAccessFile类
java.io 类 RandomAccessFile java.lang.Object java.io.RandomAccessFile1.该类不是IO流中的子类.2.该类既能读又能写.3.该对象内部 ...
- java基础知识回顾之javaIO类--File类应用:过滤器接口FilenameFilter和FileFilter
FilenameFilter和FileFilter都是用来过滤文件,例如过滤,以.jpg或者.java结尾的文件,通过看他们的源码:通过使用File类中String[] list(FilenameFi ...
- java基础知识回顾之javaIO类--File类
File类是对文件系统中文件以及目录(文件夹)进行封装的对象,可以通过面向对象的思想来操作文件和目录(文件夹).File类保存文件或目录的各种元素的信息,包括文件名,文件长度,最后修改日期,是否可读, ...
- java基础知识回顾之javaIO类总结
java IO体系图 IO流的操作规律总结: 1,明确体系: 数据源:InputStream ,Reader 数据汇:OutputStream,Writer 2,明确数据:因为数据分两种:字节,字符. ...
- java基础知识回顾之javaIO类---BufferedInputStream和BufferedOutputStream
MP3的复制过程: package com.lp.ecjtu; import java.io.BufferedInputStream; import java.io.BufferedOutputStr ...
- java基础知识回顾之javaIO类---InputStreamReader和OutputStreamWriter转化流
InputStreamReader:是字节流通向字符流的桥梁: OutputStreamWriter 是字符流通向字节流的桥梁: package com.lp.ecjtu; import java.i ...
- java基础知识回顾之javaIO类---FileInputStream和FileOutputStream字节流复制图片
package com.lp.ecjtu; import java.io.FileInputStream; import java.io.FileNotFoundException; import j ...
- java基础知识回顾之javaIO类---BufferedReader和BufferedWriter
使用了装饰设计模式:此类的设计是为了提高流操作数据的效率.思想就是定义容器将数据进行临时存储,对于缓冲区对象,其实就是将这个容器进行了分装,并提供了更高效的操作方法. BufferReader: pa ...
随机推荐
- 修改eclipse中tomcat的发布路径
当我们在eclipse部署好tomcat的时候,默认这个项目是部署在eclipse\workspace\.metadata\.plugins\org.eclipse.wst.server.core\t ...
- mysql快速上手2
上一篇文章讲的是mysql的基本操作,这一篇会有一点难以理解,本节主要内容mysql视图,存储过程,函数,事务,触发器,以及动态执行sql 视图view 视图是一个虚拟表,其内容由查询定义.同真实的表 ...
- <Linux下FTP服务的搭建>
默认安装好ftp软件包匿名用户是可以下载的.匿名以后可以上传:anon_upload_enable=YES# getsebool -a | grep ftpallow_ftpd_anon_write ...
- 我的总结SVN的使用
SVN平时在用时,一般要做到早上一次更新,中间每做出一个模块就要提交,就是一次更新,多次提交, SVN在修改公共类,配置文件时一定要注意,如果修改的是配置文件中的东西,这样修改完之后一定要提交, 如果 ...
- 使用PowerShell 连接Azure
除了使用门户登入外,还可以使用PowerShell的方式来连接Azure.首先要去下载组件 http://azure.microsoft.com/en-us/downloads/?rnd=1 http ...
- [转]bat中的特殊字符,以及需要在bat中当做字符如何处理
bat中的特殊字符,以及需要在bat中当做字符如何处理 批处理.Bat 中特殊符号的实际作用,Windows 批处理中特殊符号的作用: @ \\隐藏命令的回显. ~ \\在for中表示使用增强的变量扩 ...
- virtualbox centos安装增强工具
系统的,VBoxLinuxAdditions-amd64.run 是用于64位系统的.执行以下命令来安装sh ./VBoxLinuxAdditions-x86.run 5.安装成功后重启系统.
- awk中文手册
1. 前言 有关本手册 : 这是一本awk学习指引, 其重点着重于 : l awk 适于解决哪些问题 ? l awk 常见的解题模式为何 ? 为使读者快速掌握awk解题的模 ...
- wap_supplicant介绍
目前可以使用wireless-tools 或wpa_supplicant工具来配置无线网络.请记住重要的一点是,对无线网络的配置是全局性的,而非针对具体的接口. wpa_supplicant是一个较好 ...
- java 泛型通配符 extends, super
引自:http://sharewind.iteye.com/blog/1622164 关键字说明 ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 ...