序列号
- 序列号是序列化和反序列化的唯一标识,是一个长整型数值;
- 如果类中不自己定义序列号,系统会自动生成一个序列号;
- 当一方实体类发生改变,而调用方的序列号是不会跟着改变的,不知道对象已修改,会导致两边序列号不一致,反序列化失败;
- 所以要求必须手动生成一个序列号;
- 手动生成序列号后,可以解决目标类发生改变,不影响接口调用,对象可以正确序列化,不过对象修改的属性返序列化后没有值;
序列化对象类
//如果要支持序列化操作必须实现序列化接口 //账户类 public class Account implements Serializable { //手动生成序列号 private static final long serialVersionUID = 2116137267832764072L; //账户名 private String aname; //账户密码 private String apwd; //set,get方法省略 @Override public String toString() { return "Account{" + "aname='" + aname + ''' + ", apwd='" + apwd + ''' + '}'; } }
序列化
使用ObjectOutputStream 类的 writeObject(Object obj)方法
//序列化对象,写入文件 public static void xlhAccount() throws IOException { Account account = new Account("KH96","12345"); //使用对象输出流,将内存中的对象写入到文件 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/test/account.txt")); //直接写入对象 oos.writeObject(account); oos.close(); System.out.println("序列化对象写入成功"); }
序列化结果
反序列化
使用 ObjectInputStream 类的 readObject()方法
//反序列化目标对象读取写入序列化的文件,进行反序列化,变为写入的那个目标对象 public static void fxlhAccount() throws IOException, ClassNotFoundException { //使用对象输入流,读入写入了序列化对象的文件 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/test/account.txt")); Account account = (Account) ois.readObject(); ois.close(); //输出目标对象 System.out.println(account.toString()); System.out.println("读取序列化对象,反序列化成功"); }
反序列化结果
Account{aname='KH96', apwd='12345'} 读取序列化对象,反序列化成功
当类发生改变
改变后的序列化对象
//账户类 public class Account implements Serializable { //手动生成序列号 private static final long serialVersionUID = 2116137267832764072L; //账户名 private String aname; //账户密码 private String apwd; //添加手机 private String atel; //set,get方法省略 @Override public String toString() { return "Account{" + "aname='" + aname + ''' + ", apwd='" + apwd + ''' + ", atel='" + atel + ''' + '}'; } }
反序列化结果
Account{aname='KH96', apwd='12345', atel='null'} 读取序列化对象,反序列化成功
如果没有手动声明序列号,实体类发生改变后就会java.io.InvalidClassException异常,序列号不一致而无法进行序列化。