什么是对象的序列化?
对象的序列化是将对象状态转换为可保持或传输的格式的过程。一般的格式是与平台无关的二进制流(字节序列),可以将这种二进制流持久保存在磁盘上,也可以通过网络将这种二进制流传输到另一个网络节点。与对象序列化对应的是反序列化,是指由输入流将这种二进制流读入,重新恢复成原来的对象。
对象序列化的作用
- 远程方法调用机制,通过各个Socket作为对象之间的通信,从而实现程序组件在不同操作系统之间的通信
- 将对象转换为文件,可保存到硬盘上,以备将来继续使用该对象
- 通过序列化在进程之间传递对象
若需要某个对象能支持序列化机制,让他实现Serializable接口即可
public interface Serializable{}
此接口只是一个标记接口,实现该接口无需实现任何方法,仅仅表明该类的对象是可序列化的。
- 定义可序列化的类
import java.io.Serializable;
public class Student implements Serializable { //实现可序列化的接口
private String name;
private int age;
private String school;
public Student(){
}
public Student(String name,int age,String school){
this.name = name;
this.age = age;
this.school = school;
}
public void tell(){
System.out.println("姓名:"+name+"\t年龄:"+age+"\t学校:"+school);
}
}
Java对象被序列化时参与序列化的内容有哪些?
- 属性:基本数据类型,数组和其他对象的应用
- 类名
不能被序列化的内容有?
- 方法,类中所有的方法,记住了,是所有!!!
- static关键字和transient关键字修饰的属性
对象输出流:ObjectOutputStream
此类用于对象的序列化,即将一个对象输出
public class ObjectOutputStream extends OutputStreamimplements ObjectOutput, ObjectStreamConstants
我们可以发现ObjectOutputStream类实现看ObjectOutput接口,提供了基本的写入操作,与其他的输出流类一样,也包含write(),flush()和close()等方法
- 将对象保存在文件中
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class Demo {
public static void main(String[] args) {
Student stu1 = new Student("张三", 18, "清华大学");
Student stu2 = new Student("李四", 20, "南开大学");
File file = new File("F://student.txt"); //定义保存文件
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
oos.writeObject(stu1);
oos.writeObject(stu2);
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
这就是经过序列化的对象保存到文件中的样子
对象输入流:ObjectInputStream
此类用于对对象进行反序列化操作,从文件中将对象反序列化出来
public class ObjectInputStreamextends InputStreamimplements ObjectInput, ObjectStreamConstants
ObjectInputStream类实现了ObjectInput接口,提供了基本类型的输入方法
- 从文件中将对象反序列化
import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class Demo {
public static void main(String[] args) {
File file = new File("F://student.txt"); //定义读取文件
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(file);
ois = new ObjectInputStream(fis);
Student stu1 = (Student) ois.readObject();
Student stu2 = (Student) ois.readObject();
ois.close();
stu1.tell();
stu2.tell();
} catch (Exception e) {
e.printStackTrace();
}
}
}
姓名:张三 年龄:18 学校:清华大学
姓名:李四 年龄:20 学校:南开大学
这种使用序列化和反序列化的操作不是很好,仅仅在一些比较特殊的情况下使用。因为需要知道文件中对象的先后顺序,否则转化数据类型时将会出错。在更多的情况下会使用集合保存多个对象,然后再对集合中的对象进行序列化和反序列化操作
其实Java实现序列化有两种方式
- 实现Serializable接口 这种方式类对象的内容都将会被序列化,不需要实现任何方法
- 实现Externalizable接口 这种方式可以选择需要序列化的内容 ,需要实现接口中定义的readExternal()方法和WriteExternal()方法
一般我们常用第一种方式,第二种不常用我也就不再此进行演示了,大家可以查下相关的例子。
- 使用transient关键字声明不需要序列化的属性
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class Demo2 {
public static void main(String[] args) {
Student stu1 = new Student("张三", 18, "清华大学");
Student stu2 = new Student("李四", 20, "南开大学");
File file = new File("F://student.txt"); //定义保存文件
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
oos.writeObject(stu1);
oos.writeObject(stu2);
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
然后经过反序列化后的结果是这样的,学校这个属性就没有被序列化保存下来
姓名:张三 年龄:18 学校:null
姓名:李四 年龄:20 学校:null