黑马程序员——IO之序列化流详解

时间:2023-02-18 14:56:38

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

序列化与反序列化的说明

/*
* 序列化流与反序列化流
此流的作用就是把数据流和对象进行转换
有两个流对象
序列化流:ObjectOutputStream对象---数据流,即把对象(地址值)通过数据流写入文本
反序列化流: ObjectInputStream 数据流---对象,即可以通过读取文本来创建对象
*/

首先创建一个类,如果按照平常的方法创建后,通过序列化流写入时会报错,原因如下:

/*
* 报错:java.io.NotSerializableException为序列化异常
* 当实例需要具有序列化接口时,抛出此异常
* 说明实例(也就是本例需要序列化的对象)需要实现此Serializable接口
* 当实例实现了Serializable接口后,可以正常序列化
* Serializable接口只是一个标记接口,实现了此接口的实例可以被序列化
*/
所以该类要想被序列化就必须实现Serializable接口,该接口是一个标记接口。

当实现了Serializable后,还会出现警告,这是因为为了保证代码修改后还可以正常序列化,需要加一个标志值。

具体问题及正确代码如下:

import java.io.Serializable;

public class Person implements Serializable{

/*
* 问题一:
* Serializable接口只是一个标记接口,实现了此接口的实例可以被序列化
* 问题二:
* 但是为什么实现接口以后,类名却又黄色警戒线了呢?
* 这是因为:Person类实现了序列化接口,那么它本身也应该有一个标记值。
* 如果这个类没有给一个固定的标记值,那么一旦类中的数据被修改:如给成员变量加一个修饰词
* 那么就无法被正常反序列化
* 问题三:
* 如果我不想让某个成员变量被序列化,该怎么办呢?
* 使用transient关键字声明不需要序列化的成员变量
*/
private static final long serialVersionUID = 1L;

private String nema;
private transient int age;//此时得到的值是int类型的默认值0
/*
* 如果此时我在已经序列化后的基础上,把age变量加上了transient声明,
* 且没有定义serialVersionUID,则在反序列化时就会报错,这里验证了问题二
* 所以一旦类实现类序列化接口,一定要定义serialVersionUID,以便可以正常反序列化
* Exception in thread "main" java.io.InvalidClassException:
* cn.itcast.Person; local class incompatible:
* stream classdesc serialVersionUID = 1,
* local class serialVersionUID = -2123659650855346174
*/

public Person() {
super();
}

public Person(String nema, int age) {
super();
this.nema = nema;
this.age = age;
}

public String getNema() {
return nema;
}

public void setNema(String nema) {
this.nema = nema;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "Person [nema=" + nema + ", age=" + age + "]";
}


}
写两个方法分别实现序列化和反序列化

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/*
* 序列化流与反序列化流
此流的作用就是把数据流和对象进行转换
有两个流对象
序列化流:ObjectOutputStream对象---数据流,即把对象(地址值)通过数据流写入文本
反序列化流:ObjectInputStream数据流---对象,即可以通过读取文本来创建对象
*/
public class ObjectStream {

public static void main(String[] args) throws IOException, ClassNotFoundException {
//新定义一个类,并写方法测试
//write();
read();
}

private static void read() throws IOException, ClassNotFoundException {
//创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("o.txt"));
//还原对象
Object obj = ois.readObject();
//释放资源
ois.close();
//输出对象
System.out.println(obj);
/*
* 此时输出的是对象的地址值,要想看到对象的具体内容,需要在实例中重写toString()方法
* 重写方法后,会按照方法内容输出
*/
}

private static void write() throws IOException{
//创建序列化流对象
//public ObjectOutputStream(OutputStream out)
ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("o.txt"));
//创建对象
Person p = new Person("carry",26);
//序列化
//public final void writeObject(Object obj)
//将指定的对象写入 ObjectOutputStream
oos.writeObject(p);
//释放资源
oos.close();

}
}