当一个类的实例希望可以被对象流进行读写,那么该类必须实现序列化,即java.io.Serializable接口。
序列化接口里什么都没有,所以又称为签名接口。但是在编译后的.class文件中会添一个方法。
实现序列化会显示警告,这时要添加序列化版本号常量:serialVersionUID. 当对象输入流在进行对象反序列化时会检查该对象与当前类的版本是否一致,若一致则进行反序列化,否则反序列化时会抛出异常,导致反序列化失败。所以,序列化版本号是影响反序列化能否成功的标志。
如果我们不定义版本号,编译器会在编译当前类时根据结构信息生成一个版本号。但是一旦当前类发生改变,版本号就会发生改变,这样以前的对象就不能反序列化了。
实现序列化的类中的每个属性都自动实现序列化。但是,被transient关键字修饰的属性不被序列化,该关键字只在序列化的时候起作用。对于可存可不存的数据,就可以用transient忽略掉。
import java.io.Serializable;
public class Emp implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String gender;
private double salary;
public Emp(String name, int age, String gender, double salary) {
super();
this.name = name;
this.age = age;
this.gender = gender;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String toString() {
return name+","+age+","+gender+","+salary;
}
public boolean equals(Object o) {
if(o==null) {
return false;
}
if(o==this) {
return true;
}
if(o instanceof Emp) {
Emp emp = (Emp)o;
return emp.name==this.name && emp.age==this.age && emp.gender==this.gender && emp.salary==this.salary;
}
return false;
}
}
通过对象流写出的步骤:
- 对象流先将给定的对象转换为一组字节,这组字节包含对象的数据信息和结构信息,然后将这组字节通过其连接的流写出;
- 经过文件流时,文件流将这组字节写入到文件中。
将数据写入磁盘做长久保存的过程,叫做数据持久化。
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Scanner;
public class test09 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
ObjectOutputStream oos = null;
try {
File file = new File("src/main/java/exercise/emp.txt");
oos = new ObjectOutputStream(new FileOutputStream(file));
ArrayList<Emp> arr = new ArrayList<Emp>();
String line = null;
System.out.println("请输入员工信息:");
while(true) {
line = scan.nextLine();
if("exit".equals(line)) {
break;
}
String[] info = line.split(",");
String name = info[0];
int age = Integer.parseInt(info[1]);
String gender = info[2];
double salary = Double.parseDouble(info[3]);
Emp employee = new Emp(name,age,gender,salary);
arr.add(employee);
}
oos.writeObject(arr);
System.out.println("员工信息录入完毕!");
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
oos.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
对象输入流可以进行对象的反序列化操作。注意,使用对象流读取的字节必须是通过对象输出流序列化的一组字节才可以。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Arrays;
public class Test06 {
public static void main(String[] args) {
try {
File file = new File("src/main/java/exercise/emp.txt");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
ArrayList<Emp> arr = new ArrayList<Emp>();
arr = (ArrayList<Emp>) ois.readObject();
for(int i=0;i<arr.size();i++) {
System.out.println(arr.get(i));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}