javaIO——序列化与反序列化

本节目标:

    1.掌握序列化的作用

    2.掌握Serializable接口的作用

    3.使用ObjectOutputStream进行对象序列化操作

    4.使用ObjectInputStream进行对象的反序列化操作

    5.掌握Externalizable接口的作用,及与Serializable接口的区别

    6.掌握transient关键字的作用

    7.序列化一组对象

对象序列化

    一个对象产生后,实际上是在内存中为其开辟了一个存储空间,进行存储信息。对象序列化,就是把一个对象变为二进制流的一种方法,通过对象序列化,方便对象的传输或存储。


如果一个类的对象想被序列化,可以实现Serializable接口。该接口没有定义任何方法,是一个标识接口,表示具备了某种能力。

对象的序列化与反序列化

想要完成对象的输入与输出,必须依靠对象输出流ObjectOutputStream和对象输入流ObjectInputStream。

使用ObjectOutputStream输出序列化对象的过程,叫做对象的序列化;

使用ObjectInputStream读入对象的过程,叫做对象的反序列化。


注意:在对象进行序列化或反序列化的时候,需要考虑JDK版本的问题,如果序列化的JDK版本与反序列化的版本不统一则会产生异常,所以在序列化的时候会引入一个serialVersionUID的常量,可以通过此常量验证版本是否一致。在进行反序列化的时候,JVM会把传来的字节流中的serialVersionUID与被序列化类中的serialVersionUID进行比较,如果相同,可以进行反序列化。

如定义一个可以序列化的类:

public class Persion implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Persion(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Persion [name=" + name + ", age=" + age + "]";
}
}

此类的对象就可以被序列化了,变为二进制byte流。

对象序列化与反序列化操作

对象序列化依靠ObjectOutputStream,对象反序列化依靠ObjectInputStream。

序列化:ObjectOutputStream

java.lang.Object
  java.io.OutputStream
      java.io.ObjectOutputStream
所有已实现的接口:
CloseableDataOutputFlushableObjectOutputObjectStreamConstants

此类的使用与PrintStream类似,需要接收一个OutputStream子类对象,根据传入的子类对象的不同,输出的位置也不同。

public class SerDemo1 {
public static void main(String[] args) throws IOException {
File f = new File("f:" + File.separator + "test.txt");//定义存放路径
OutputStream out = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(new Persion("张三", 20));
oos.close();
}

}

到底序列化了些什么内容呢?

所有的对象都有各自的属性值,但是所有的方法都是公共的,所以序列化对象的时候 实际上序列化的是属性。

反序列化:ObjectInputStream

java.lang.Object
  java.io.InputStream
      java.io.ObjectInputStream
所有已实现的接口:
CloseableDataInputObjectInputObjectStreamConstants

此类是InputStream的子类,与PrintStream类似,需要接收一个InputStream子类对象。

public class DserDemo1 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
File f = new File("f:" + File.separator + "test.txt");
InputStream is = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(is);//对象输入流
Object obj = ois.readObject();
is.close();
System.out.println(obj);
}

}

Externalizable接口

用户如果希望自己指定序列化的内容,可以实现Externalizable接口。

public interface Externalizable extends Serializable{ 
readExternal(ObjectInput in) //读取
writeExternal(ObjectOutput out) //写入

}

例如:

public class Persion2 implements Externalizable {
private String name;
private int age;
public Persion2() {}
public Persion2(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Persion2 [name=" + name + ", age=" + age + "]";
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(this.name);//保存名称属性
out.writeInt(this.age);//保存年龄属性
}
@Override
public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {
this.name = (String) in.readObject();
this.age = in.readInt();
}
}

public class ExterDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// ser();
dser();
}
//序列化
public static void ser() throws IOException{
File f = new File("f:" + File.separator + "test.txt");//定义存放路径
OutputStream out = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(new Persion2("张三", 20));
oos.close();
}
//反序列化
public static void dser() throws IOException, ClassNotFoundException{
File f = new File("f:" + File.separator + "test.txt");
InputStream is = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(is);//对象输入流
Object obj = ois.readObject();
is.close();
System.out.println(obj);
}
}

在使用Externalizable接口的时候需要在被序列化的类中定义一个无参构造,因为在进行反序列化的时候会用到这个无参构造方法进行实例化,之后再设置属性值。否则会出现no valid constructor异常。

Externalizable与Serializable的区别:


在开发中,多使用Serializable接口。

transient关键字

在序列化操作的时候,如果希望某个属性不被序列化,可以使用transient关键字声明。例如:

public class Persion implements Serializable {
private static final long serialVersionUID = 1L;
private transient String name;//该属性不被序列化
private int age;
public Persion(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Persion [name=" + name + ", age=" + age + "]";
}
}

transient+Serializable完全可以取代Externalizable的功能。

序列化一组对象

要想序列化一组对象的时候,可以使用对象数组进行操作。因为数组是引用类型,可以使用Object类型接收。


public class SerDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Persion[] p = {new Persion("张三",20),new Persion("李四",22),new Persion("王五",24)};
ser(p);
Persion[] per = (Persion[]) dser();
for (int i = 0; i < per.length; i++) {
System.out.println(per[i]);
}
}
//序列化
public static void ser(Object[] obj) throws IOException{
File f = new File("f:" + File.separator + "test.txt");//定义存放路径
OutputStream out = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(obj);
oos.close();
}
//反序列化
public static Object[] dser() throws IOException, ClassNotFoundException{
File f = new File("f:" + File.separator + "test.txt");
InputStream is = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(is);//对象输入流
Object[] obj = (Object[]) ois.readObject();
is.close();
return obj;
}
}

总结:

1.对象序列化并不一定保存到文件中,可以面向其他的输入或输出。

2.被序列化对象的类必须实现Serializable接口,如果某个属性不希望被保存,可以使用transient关键字声明。

3.对象序列化依靠ObjectOutputStream,对象反序列化依靠ObjectInputStream。

4.Externalizable可以手工序列化

5.使用对象数组对多个对象进行序列化。








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值