对象序列化:把Java对象转换为字节序列的过程;
对象反序列化:把字节序列恢复为Java对象的过程;
●对象序列化的来源:
实际网络上发送信息时,往往会把一组信息封装成一个对象;即网络传输时经常会遇到如何发送对象的内容和如何解析对象的内容的问题。就是对象序列化要解决的问题。
以前做项目的时候,也遇到对象序列化~~~
●对象序列化的步骤:
(1)创建一个类,这个类需要继承Serializable接口;一个类只有继承了Serializable接口,这个类的对象才能在网络上进行读写传输;
(2)创建对象;
(3)将对象写入文件;(实际上是写入到网络中的,这儿为了方便演示,写入到文件中了,以后了解到网络传输时,再回头看看)
(4)从文件中读取对象信息;(实际上是从网络中读取对象的,这儿为了方便演示,改成文件了,以后了解到网络传输时,再回头看看)
●对象的读写需要用到:
ObjectInputStream:对象输入流
ObjectOutputStream:对象输出流 (这两个类是字节流的子类)
一:ObjectOutputStream和ObjectInputStream简述
需要注意,在构建ObjectOutputStrea和ObjectInputStream对象流时,需要借助一个OutputStream和InputStream。一般使用FileOutputStream类和FileInputStream类对象。
ObjectOutputStream:
构造方法:

其常用方法有:close(),flush(),writeObject(Object obj)等,可查API。
……………………………………………………
ObjectInputStream:
构造方法:

其常用方法有:close(),readLine()(这个的读取一行常用不?),readObject()。其中,readObject()负责去读取writeObject(Object obj)写的数据,这俩成对使用。
二:ObjectOutputStream和ObjectInputStream示例
Goods类时待序列化和反序列化的类,其需要实现Serializable接口
// Goods实现Serializable接口
public class Goods implements Serializable{
private String goodsId;
private String goodsName;
private double price;
public Goods(){}
public Goods(String goodsId,String goodsName,double price){
this.goodsId = goodsId;
this.goodsName = goodsName;
this.price = price;
}
public String getGoodsId() {
return goodsId;
}
public void setGoodsId(String goodsId) {
this.goodsId = goodsId;
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString(){
return goodsId+" "+goodsName+" "+price;
}
}
示例一:ObjectOutputStream输出范例:(对于对象序列化和反序列化,一般是先输出才有输入哦;就像在网络传输中,只有一方发出了,另一方才能接收一样。)
public class SerialTest {
public static void main(String[] args) {
Goods good1 = new Goods("gd01","电脑",3000);
try {
// (1)构建OutputStream对象,因为ObjectOutputStream的构造方法需要用到
FileOutputStream fos = new FileOutputStream("imooc.txt");
// (2)构建ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
// (3)开始写
oos.writeObject(good1); // 将对象写入到文件中,也实现了一个持久化的存储
// (4)flush(),和close()
oos.flush();
fos.close();oos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
}
}
输出结果是乱码,很正常,这其中可能像http报文格式那样,不仅有对象信息,还有各种辅助标识信息等。本来就不是给人直接用眼看的。

……………………………………………………
示例二:ObjectOutputStream和ObjectInputStream范例:写读一个Goods对象
public class SerialTest {
public static void main(String[] args) {
Goods good1 = new Goods("gd01","电脑",3000);
try {
// (1)构建OutputStream对象,因为ObjectOutputStream的构造方法需要用到
FileOutputStream fos = new FileOutputStream("imooc.txt");
// (2)连接文件输出流,构建ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
// (3)构建InputStream对象,因为ObjectInputStream的构造方法需要用到
FileInputStream fis = new FileInputStream("imooc.txt");
// (4)连接文件输出流,构建ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(fis);
// (5)将对象信息写入文件
oos.writeObject(good1); // 将对象写入到文件中,也实现了一个持久化的存储
// (6)flush()
oos.flush();
// (7)从文件中读取对象数据
Goods good = (Goods)ois.readObject(); //这条语句需要捕获 ClassNotFoundException异常
// (8)打印对象,验证是否正确读取对象
System.out.println(good);// 输出对象(调用toString方法),验证对象是否被正确读出来
// (9)调用close方法
fos.close();oos.close();fis.close();ois.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} catch( ClassNotFoundException e){
e.printStackTrace();
}
}
}
输出结果:发现,可以正常识别Goods对象

……………………………………………………
示例三:ObjectOutputStream和ObjectInputStream范例:写读Goods对象和Boolean对象
(1)注意有 //*******的是新增内容
(2)可以发现ObjectOutputStream和ObjectInputStream类中,有多种类型的write方法和read方法,以方便写读各种类型的对象;(大概率是不同类型的对象的诸如结尾符号,分隔符等等的标识信息不一样,所以需要不同的写读方法)
public class SerialTest {
public static void main(String[] args) {
Goods good1 = new Goods("gd01","电脑",3000);
try {
// (1)构建OutputStream对象,因为ObjectOutputStream的构造方法需要用到
FileOutputStream fos = new FileOutputStream("imooc.txt");
// (2)连接文件输出流,构建ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
// (3)构建InputStream对象,因为ObjectInputStream的构造方法需要用到
FileInputStream fis = new FileInputStream("imooc.txt");
// (4)连接文件输出流,构建ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(fis);
// (5)将对象信息写入文件
oos.writeObject(good1); // 将对象写入到文件中,也实现了一个持久化的存储
oos.writeBoolean(true); //**********写入Boolean的对象,包装类吧应该
// (6)flush()
oos.flush();
// (7)从文件中读取对象数据
Goods good = (Goods)ois.readObject(); //这条语句需要捕获 ClassNotFoundException异常
// (8)打印对象,验证是否正确读取对象
System.out.println(good);// 输出对象(调用toString方法),验证对象是否被正确读出来
boolean bool = ois.readBoolean(); //**********读取Boolean对象并输出
System.out.println(bool);
// (9)调用close方法
fos.close();oos.close();fis.close();ois.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} catch( ClassNotFoundException e){
e.printStackTrace();
}
}
}
输出结果:可以正常读出Goods对象和Boolean对象

注:(1)
(2)可知我们存的时候,是先存的Goods对象,后存的Boolean对象,自然读的时候,先读出来的是Goods对象,如果读的是Goods对象,而用Boolean类型对象接收会引发EOFException结尾异常。

……………………………………………………
示例四:ObjectOutputStream和ObjectInputStream范例:写读多个Goods对象

……………………………………………………
示例五:ObjectOutputStream和ObjectInputStream范例:写读Goods对象和Goodss对象
(注:其中Goodss类内容和Goods类内容类似,这儿仅仅是展示多种类对象的存储示例)

……………………………………………………
由上面的例子,可以看到,由几个问题需要验证下:
(1)有没有一个统一的read()方法,该方法可以返回一个对象;有没有判断该次read方法读取的对象是什么类型的方法;有没有判断还有没有没读完的对象的类似迭代器那样的方法?这些问题,
三:常见问题
问题一:有什么方法可以判断文件中的对象是否读完并循环输出
可以手动在最后写入一个结束标识null,oss.writeObject(null)
读的判定条件是 ois.readObject != null;

使用try-catch语句块,捕获EOFException异常,并提示“已经温泉读入即可”;

经过实测,上面的策略是可以的;上面的异常,应该是为了防止已经读完了,但任然继续读了最后的一个null对象而准备的。
问题二:流的关闭顺序
建议,先打开的先关闭,后打开的后关闭。
问题三:对象序列化的文件乱码
对象输出流写到文件中的东西,其本身不是文本数据,是对象序列化后的数据,所以乱码是正常的;
问题四:为什么需要flush方法
Java在使用流时,会有一个小的缓冲,就像一个管道一样,输出的时候通过管道存到介质上(硬盘或其他),当输出完成后管道里面可能还有残余,使用flush方法可以清空管道将残余内容全部存到介质上。
940

被折叠的 条评论
为什么被折叠?



