勿以恶小而为之,勿以善小而不为--------------------------刘备
劝诸君,多行善事积福报,莫作恶
上一章简单介绍了 DataOutputStream和DataInputStream(八),如果没有看过,请观看上一章
一. 为什么要序列化?
上一章节写入文件的员工列表信息数据:
id
| name
| sex
| age
| desc
|
1
| 老蝴蝶
| 男
| 20
| 一个好人
|
2
| 蝴蝶
| 男
| 21
| 一个人
|
3
| 岳泽霖
| 男
| 22
| 快乐的人
|
4
| 岳建立
| 男
| 23
| 想要快乐的人
|
通过 DataOutputStream 和 DataInputStream ,发现太复杂了,需要固定的格式进行处理, 当数据信息复杂时,就疯了。
我们发现,员工的信息可以封装成一个对象,如 Person 对象, 该对象里面有 id,name,sex,age,desc 属性。
public class Person {
private int id;
private String name;
private char sex;
private int age;
private String desc;
public Person() {
}
public Person(int id, String name, char sex, int age, String desc) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
this.desc = desc;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
", desc='" + desc + '\'' +
'}';
}
}
我们存储时,能直接存储对象就好了, 取数据时,直接取对象, 方便操作。
这种形式,其实就是序列化。
序列化是将对象存储到文件里面, 反序列化是将文件转换成对象。
序列化和反序列化所需要的对象为 ObjectOutputStream 和 ObjectInputStream.
二. 序列化 ObjectOutputStream
二.一 方法
二.一.一 构造方法
二.一.一.一 方法
方法
| 作用
|
ObjectOutputStream(OutputStream out)
| 传入 outputStream 对象
|
二.一.一.二 演示
@Test
public void objConTest() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data2.txt");
//传入 outputStream
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(file));
}
二.一.二 写入方法
方法
| 作用
|
void flush()
| 刷新此数据输出流
|
void writeInt(int v)
| 写入 int 类型的值
|
void writeLong(long v)
| 写入long 类型的值
|
void writeFloat(float v)
| 写入float 值
|
void writeDouble(double v)
| 写入double 值
|
void writeBoolean(boolean v)
| 写入boolean 类型的值
|
void writeChar(int v)
| 写入char 类型的值, 可以直接写入单个中文字符。 可写入 \t 和\n
|
void writeChars(String s)
| 写入字符串
|
void writeUTF(String str)
| 使用机器无关的方式使用 modified UTF-8编码将字符串写入底层输出流。
|
void writeObject(Object obj)
| 写入对象
|
对于 ObjectOutputStream 对象,只需要记住 writeObject() 方法即可。
二.二 演示 ObjectOutputStream
在序列化对象之前, 必须要保证 那个实体类, 即 Person 类,实现了 java.io.Serializable 接口, 否则会抛出异常的。
public class Person implements Serializable {
}
二.二.一 写入 单个对象
@Test
public void write1Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data2.txt");
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(file));
Person person=new Person(1,"两个蝴蝶飞",'男',24,"一个快乐的程序员");
//如果没有序列化,会报错。
objectOutputStream.writeObject(person);
objectOutputStream.close();
}
运行程序, 查看 data2.txt 文件内容:
大概可以猜测是三部分, 第一部分是 类全限定名称, 第二部分是属性, 第三部分是 数据。
二.二.二 写入集合对象
同样是 writeObject ()方法处理。
@Test
public void write2Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data3.txt");
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(file));
Person person1=new Person(1,"两个蝴蝶飞1",'男',24,"一个快乐的程序员1");
Person person2=new Person(2,"两个蝴蝶飞2",'男',24,"一个快乐的程序员2");
Person person3=new Person(3,"两个蝴蝶飞3",'男',24,"一个快乐的程序员3");
Person person4=new Person(4,"两个蝴蝶飞4",'男',24,"一个快乐的程序员4");
Person[] ps=new Person[]{person1,person2,person3,person4};
//如果没有序列化,会报错。
objectOutputStream.writeObject(ps);
objectOutputStream.close();
}
运行程序,查看 data3.txt
我们虽然看不懂,但 ObjectInputStream 却能看懂,能解析。
三. 反序列化 ObjectInputStream
三.一 方法
三.一.一 构造方法
三.一.一.一 方法
方法
| 作用
|
ObjectInputStream(InputStream in)
| 传入 inputStream 对象
|
三.一.一.二 演示
@Test
public void readConTest() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data2.txt");
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
}
三.一.二 读取方法
方法
| 作用
|
int readInt()
| 读取 int ,实际上就是读取4个长度
|
long readLong()
| 读取 long
|
float readFloat()
| 读取float
|
double readDouble()
| 读取double
|
boolean readBoolean()
| 读取boolean
|
char readChar()
| 读取char, 实际内部读取两个字节
|
String readUTF()
| 读取字符串
|
Object readObject()
| 读取对象
|
对于 ObjectInputStream 对象,只需要记住 readObject() 方法即可。
三.二 演示 ObjectInputStream
三.二.一 读取序列化的单个对象
@Test
public void read1Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data2.txt");
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
Object obj= objectInputStream.readObject();
//向上转型
Person person=(Person)obj;
System.out.println("员工:"+person.toString());
objectInputStream.close();
}
运行程序,查看控制台打印输出:
三.二.二 读取序列化的对象集合
@Test
public void read2Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data3.txt");
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
Object readObj= objectInputStream.readObject();
//对象数组
Object[] objs=(Object[])readObj;
for(Object obj:objs){
//对每一个进行强制转换。
Person person=(Person)obj;
System.out.println("员工:"+person);
}
objectInputStream.close();
}
运行程序,查看控制台打印输出:
可以正确的读取。
四. 序列化部分属性 transient
有时候,一个实体类中属性过多,不需要全部保存起来,或者某个属性太重要,需要保证安全,不能存储起来, 那么就需要 使用 transient 关键字进行阻止序列化。
如 阻止序列化 name 和 sex
重新运行一下 write2Test() 和 read2Test() 方法,查看控制台
就发现, name 和 sex 没有被序列化。
五. Externalizable 接口实现序列化
除了 Serializable 接口可以实现序列化外,还可以使用 java.io.Externalizable 接口 进行序列化, 但常用的还是 Serializable 接口, 这个接口 Externalizable 只需要了解即可。
package java.io;
import java.io.ObjectOutput;
import java.io.ObjectInput;
/**
* @since JDK1.1
*/
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
writeExternal() 方法 设置的是 保存哪些属性,
readExternal() 方法,设置的是读取哪些属性。
注意,保存和读取属性的顺序 必须保持一致。
五.一 Externalizable 实现序列化
五.一.一 实体类 实现 接口
public class Person2 implements Externalizable {
}
五.一.二 重写 writeExternal() 方法,设置保存的属性
@Override
public void writeExternal(ObjectOutput out) throws IOException {
//保存哪些, 保存的数据。
out.writeInt(id);
out.writeObject(name);
//不保存 sex 属性
out.writeInt(age);
out.writeObject(desc);
}
五.一.三 重写 readExternal() 方法,读取保存的属性
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
//读取的, 按照保存的顺序读取
this.id=in.readInt();
this.name=(String)in.readObject();
this.age=in.readInt();
this.desc=(String)in.readObject();
}
五.一.四 序列化单个对象
@Test
public void write1Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data4.txt");
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(file));
Person2 Person2=new Person2(1,"两个蝴蝶飞",'男',24,"一个快乐的程序员");
//如果没有序列化,会报错。
objectOutputStream.writeObject(Person2);
objectOutputStream.close();
}
与 以前的方法是一样的。
运行程序,查看 data4.txt 的内容。
五.一.五 反序列化单个对象
@Test
public void read1Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data4.txt");
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
Object obj= objectInputStream.readObject();
Person2 Person2=(Person2)obj;
System.out.println("员工:"+Person2);
objectInputStream.close();
}
运行程序:
对象集合的序列化和反序列化与以前的也是一样的,就不重复写了。
五.二 Serializable 和 Externalizable 的区别
区别
| Serializable
| Externalizable
|
实现上
| 实现简单,Java提供了支持
| 实现复杂,需要开发人员写保存和读取
|
执行效率上
| 由Java统一 保存,性能较低
| 开发人员决定,速度可能会高
|
保存信息所占空间
| 空间大
| 空间较小
|
开发中,常使用的是 Serializable
序列化非常重要,一定要掌握。
谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!