对象的输入输出流 : 主要的作用是用于写入对象信息与读取对象信息。 对象信息一旦写到文件上那么对象的信息就可以做到持久化了
  对象的输出流: ObjectOutputStream
  对象的输入流:  ObjectInputStream

使用:

对象的输出流将指定的对象写入到文件的过程,就是将对象序列化的过程,对象的输入流将指定序列化好的文件读出来的过程,就是对象反序列化的过程。既然对象的输出流将对象写入到文件中称之为对象的序列化,那么可想而知对象所对应的class必须要实现Serializable接口。(查看源码可得知:Serializable接口没有任何的方法,只是作为一个标识接口存在)。

1、将User类的对象序列化

 class User implements Serializable{//必须实现Serializable接口
String uid;
String pwd;
public User(String _uid,String _pwd){
this.uid = _uid;
this.pwd = _pwd;
}
@Override
public String toString() {
return "账号:"+this.uid+" 密码:"+this.pwd;
}
} public class Demo1 { public static void main(String[] args) throws IOException {
//假设将对象信息写入到obj.txt文件中,事先已经在硬盘中建立了一个obj.txt文件
File f = new File("F:\\obj.txt");
writeObjec(f);
System.out.println("OK");
} //定义方法把对象的信息写到硬盘上------>对象的序列化。
public static void writeObjec(File f) throws IOException{
FileOutputStream outputStream = new FileOutputStream(f);//创建文件字节输出流对象
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(new User("酒香逢","123"));
//最后记得关闭资源,objectOutputStream.close()内部已经将outputStream对象资源释放了,所以只需要关闭objectOutputStream即可
objectOutputStream.close();
}
}

运行程序得到记事本中存入的信息:可见已经序列化到记事本中

2、将序列化到记事本的内容反序列化

 public class Demo1 {

     public static void main(String[] args) throws IOException, ClassNotFoundException {
//假设将对象信息写入到obj.txt文件中,事先已经在硬盘中建立了一个obj.txt文件
File f = new File("F:\\obj.txt");
//writeObjec(f);
readObject(f);
System.out.println("OK");
} //定义方法把对象的信息写到硬盘上------>对象的序列化。
public static void writeObjec(File f) throws IOException{
FileOutputStream outputStream = new FileOutputStream(f);//创建文件字节输出流对象
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(new User("酒香逢","123"));
//最后记得关闭资源,objectOutputStream.close()内部已经将outputStream对象资源释放了,所以只需要关闭objectOutputStream即可
objectOutputStream.close();
}
//把文件中的对象信息读取出来-------->对象的反序列化
public static void readObject(File f) throws IOException, ClassNotFoundException{
FileInputStream inputStream = new FileInputStream(f);//创建文件字节输出流对象
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
User user = (User)objectInputStream.readObject();
System.out.println(user);
}
}

运行代码得到的结果:

账号:酒香逢 密码:123
OK

但是,如果这时候这个obj.txt是我们项目中一个文件,而项目到后期在原来User类的基础上添加成员变量String userName;

 class User implements Serializable{//必须实现Serializable接口
String uid;
String pwd;
String userName="名字";//新添加的成员变量
public User(String _uid,String _pwd){
this.uid = _uid;
this.pwd = _pwd;
}
@Override
public String toString() {
return "账号:"+this.uid+" 密码:"+this.pwd;
}
}

这时候如果我们再反序列化,则会引发下面的异常:

Exception in thread "main" java.io.InvalidClassException: xuliehua.User; local class incompatible: stream classdesc serialVersionUID = 2161776237447595412, local class serialVersionUID = -3634244984882257127
  at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:604)
  at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1601)
  at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1514)
  at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
  at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
  at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
  at xuliehua.Demo1.readObject(Demo1.java:48)
  at xuliehua.Demo1.main(Demo1.java:32)

异常信息解读:

serialVersionUID 是用于记录class文件的版本信息的,serialVersionUID这个数字是JVM(JAVA虚拟界)通过一个类的类名、成员、包名、工程名算出的一个数字。而这时候序列化文件中记录的serialVersionUID与项目中的不一致,即找不到对应的类来反序列化。

3、如果序列化与反序列化的时候可能会修改类的成员,那么最好一开始就给这个类指定一个serialVersionUID,如果一类已经指定的serialVersionUID,然后
在序列化与反序列化的时候,jvm都不会再自己算这个 class的serialVersionUID了。

去掉刚才添加的成员变量userName;,并且在User类中指定一个serialVersionUID

 class User implements Serializable{//必须实现Serializable接口

     private static final long serialVersionUID = 1L;
String uid;
String pwd;
//String userName="名字";//新添加的成员变量
public User(String _uid,String _pwd){
this.uid = _uid;
this.pwd = _pwd;
}
@Override
public String toString() {
return "账号:"+this.uid+" 密码:"+this.pwd;
}
}

重新序列化到obj.txt文件中,然后再类中再将userName添加回来(将上面User类中userName字段解注释),再一次执行反序列化操作,执行的结果跟之前反序列化的结果是一致的。可见这样解决后我们后期修改类也是可行的。

4、如果在User类中再添加成员变量,而这个变量为一个class ,如Address,那么Address类也必须要实现Serializable接口。

 class Address implements Serializable{
String country;
String city;
} class User implements Serializable{//必须实现Serializable接口 private static final long serialVersionUID = 1L;
String uid;
String pwd;
String userName="名字";//新添加的成员变量
Address address;//成员变量为Address
public User(String _uid,String _pwd){
this.uid = _uid;
this.pwd = _pwd;
}
@Override
public String toString() {
return "账号:"+this.uid+" 密码:"+this.pwd;
}
}

5、最后再提一下关键字transient关键字,当你不想要某些字段序列化时候,可以用transient关键字修饰

 class User implements Serializable{//必须实现Serializable接口

     private static final long serialVersionUID = 1L;
String uid;
String pwd;
transient String userName="名字";//新添加的成员变量//添加关键字transient后,序列化时忽略
Address address;//成员变量为Address
public User(String _uid,String _pwd){
this.uid = _uid;
this.pwd = _pwd;
}
@Override
public String toString() {
return "账号:"+this.uid+" 密码:"+this.pwd;
}
}

最后总结一下对象输入输出流使用时需要注意:

1. 如果对象需要被写出到文件上,那么对象所属的类必须要实现Serializable接口。 Serializable接口没有任何的方法,是一个标识接口而已。
2. 对象的反序列化创建对象的时候并不会调用到构造方法的、(这点文中没有说到,想要验证的同学在构造方法后面加一句System.out.println("构造方法执行吗?");,实际上构造方法是不执行的,自然这句话也没有输出了)
3. serialVersionUID 是用于记录class文件的版本信息的,serialVersionUID这个数字是通过一个类的类名、成员、包名、工程名算出的一个数字。
4. 使用ObjectInputStream反序列化的时候,ObjeectInputStream会先读取文件中的serialVersionUID,然后与本地的class文件的serialVersionUID
进行对比,如果这两个id不一致,反序列则失败。
5. 如果序列化与反序列化的时候可能会修改类的成员,那么最好一开始就给这个类指定一个serialVersionUID,如果一类已经指定的serialVersionUID,然后
在序列化与反序列化的时候,jvm都不会再自己算这个 class的serialVersionUID了。
6. 如果一个对象某个数据不想被序列化到硬盘上,可以使用关键字transient修饰。
7. 如果一个类维护了另外一个类的引用,则另外一个类也需要实现Serializable接口。

(JAVA)从零开始之--对象输入输出流ObjectInputStream、ObjectOutputStream(对象序列化与反序列化)的更多相关文章

  1. 对象输入输出流ObjectInputStream、ObjectOutputStream(对象序列化与反序列化)

    对象的输入输出流 : 主要的作用是用于写入对象信息与读取对象信息. 对象信息一旦写到文件上那么对象的信息就可以做到持久化了 对象的输出流: ObjectOutputStream 对象的输入流:  Ob ...

  2. 对象输入输出流ObjectInputStream、ObjectOutputStream(对象的序列化与反序列化)

    如题 所有关联的类需要继承Serializable 接口 文件为空,直接反序列化为发生错误; 毕竟对象为null , 序列化到文件里不是空空的! 以下笔记的原文连接: https://www.cnbl ...

  3. 输入输出流ObjectInputStream、ObjectOutputStream(对象序列化与反序列化)

    对象的输入输出流 : 主要的作用是用于写入对象信息与读取对象信息. 对象信息一旦写到文件上那么对象的信息就可以做到持久化了 对象的输出流: ObjectOutputStream 对象的输入流:  Ob ...

  4. Day 18:SequenceInputStream、合并切割mp3、对象输入输出流对象

    SequenceInputStream用例题讲述用法 需求:1.把a.txt与b.txt 文件的内容合并 2.把a.txt与b.txt .c.txt文件的内容合并 import java.io.Fil ...

  5. java 对象输入输出流

    对象的输入输出流的作用: 用于写入对象 的信息读取对象的信息. 对象的持久化. 比如:用户信息.              ObjectInputStream   : 对象输入流            ...

  6. serialVersionUID序列化版本号与ObjectOutputStream对象输入输出流

    1. 观察ObjectOutputStream 我们观察ObjectOutputStream就可以发现该类没有无参构造,只有有参构造,所以他是一个包装流 2. 具体使用: public static ...

  7. 详解Java中的IO输入输出流!

    目录 本片要点 基本分类 发展史 文件字符流 输出的基本结构 流中的异常处理 异常处理新方式 读取的基本结构 运用输入与输出完成复制效果 文件字节流 缓冲流 字符缓冲流 装饰设计模式 转换流(适配器) ...

  8. JAVA之I/O 输入输出流详解

    简    介 如何在Java中进行文件的读写,Java IO流是必备的知识.这篇博文主要为您带来Java中的输入输出流的内容,包括文件编码.使用File类对文件和目录进行管理.字节流和字符流的基本操作 ...

  9. Java修炼——文件字节输入输出流复制和缓冲流复制

    一:文件字节输入输出流复制 首先明确数据源和目的文件,然后就是"中转站",最后就是关闭 package com.bjsxt.ioproject; import java.io.Fi ...

随机推荐

  1. 搜索提示時jquery的focusout和click事件沖突問題完美解决

          在主流的搜索引擎上搜索時,輸入內容,往往會彈出智能提示.輸入框为input,智能提示區域为suggest.接下來一般有兩種操作:        1.選擇某一提示,則把內容复制到input中 ...

  2. NOI题库7624 山区建小学(162:Post Office / IOI2000 POST OFFICE [input] )

    7624:山区建小学 Description 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为 ...

  3. Error: rpmdb open failed

    yumrpmdb: Thread/process 17132/140266190264064 failed: Thread died in Berkeley DB l                  ...

  4. openStack云平台虚拟桌面galera mysql 3节点集群实例实战 调试完成

    被复制节点: /usr/local/mysql/bin/mysqld_safe --wsrep_cluster_address=gcomm:// >/dev/null &复制节点01: ...

  5. Erasing Edges - SGU 136(构造多边形)

    题目大意:已知一个多边形上的每条边的中点,还原出来一个多边形. 分析:因为偶数是不固定的,所以可以为任意起点,奇数只有一个,可以所有中点加减算出来第一个点,然后就是简单的向量计算点的位置了...... ...

  6. rnqoj-73-展演队型-dp

    纯属于敢想就敢做的题目,列出来状态转移就OK了 #include<stdio.h> #include<string.h> #include<iostream> #i ...

  7. UVa1607 poj1435 UVaLive1686 Gates

    填坑系列(p.246) 由函数连续性得满足二分性 #include<cstdio> #include<cstring> #include<cstdlib> #inc ...

  8. 使用Morphia框架操作mongodb

    1.  mac 下 安装mongodb sudo brew update sudo brew install mongodb sudo brew services mongodb start 2.   ...

  9. 语音控制的tab选项卡

    前端开发whqet,csdn,王海庆,whqet,前端开发专家 ladies and 乡亲们,程序猿同志们,周末仍然坚守工作岗位,或者学习不辍的童鞋们,福音来了. 语音识别高不高端.难不难? 今天给大 ...

  10. Android ADT离线更新办法

    Troubleshooting ADT Installation If you are having trouble downloading the ADT plugin after followin ...