zoukankan      html  css  js  c++  java
  • java序列化

    Java序列化Serialize

    序列化与反序列化

    序列化:把对象写入到流中

    反序列化:把对象从流中读取出来

    什么情况下序列化

    1. 对象需要通过网络进行传输
    2. 需要持久化对象到磁盘
    3. 需要持久化对象到数据库(把对象通过字节流的方式存储)

    序列化的实现方式

    实现Serializable接口

    • Serializable是一个标记接口,接口中没有任何方法
    • 需要序列化的对象除基本数据类型属性外其他属性也必须实现Serializable接口
    public class Student implements Serializable{
    
    	private static final long serialVersionUID = 2992794326818594180L;
    	
    	private String name;
    	private int age;
    	//省略constructor、setter、getter、toString
    }
    
    @Test
    public void test1() throws Exception {
      Student s1=new Student("tom",20);
      System.out.println(s1);
      ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
      oos.writeObject(s1);
    
      ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
      Student s2=(Student)ois.readObject();
      System.out.println(s2);
    }
    输出:
    Student [name=tom, age=20]
    Student [name=tom, age=20]
    

    如果序列化对象的非基本数据类型属性没有实现Serialize接口,会抛出NotSerializableException异常

    public class Student implements Serializable{
    
    	private static final long serialVersionUID = 2992794326818594180L;
    	
    	private String name;
    	private int age;
    	private School school;
    	//省略constructor、setter、getter、toString
    }
    class School{
    	private String name;
    	//省略constructor、setter、getter、toString
    }
    
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
      Student s1=new Student("tom",20,new School("xw"));
      System.out.println(s1);
      ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
      oos.writeObject(s1);
    
      ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
      Student s2=(Student)ois.readObject();
      System.out.println(s2);
    }
    
    输出:
    java.io.NotSerializableException: com.moyuduo.analyze.School
    

    实现Externaliable接口并实现方法

    • 序列化对象的非基本数据类型外其他类型必须实现Serializable接口或Externaliable接口
    • 实现Externaliable的类必须提供无参构造器,因为在反序列化的时候需要使用无参构造器创建对象

    这种方式比实现Serializable接口略复杂,但是可以实现更加复杂的控制,因为实现Externaliable接口重写方法需要我们自己指定序列化规则(可以对序列化进行加密产生字节)和反序列化规则(序列化规则的逆过程)

    实现Externaliable接口方式比实现Serializable接口方式的效率高

    public class Student implements Externalizable{
    
    
      private String name;
      private int age;
      private School school;
    
      public Student() {//必须加无参构造器
        System.out.println("Student无参构造器");
      }
      //省略有参constructor、setter、getter、toString
      @Override
      public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(new StringBuffer(this.name).reverse().toString());
        out.writeInt(this.age);
        out.writeObject(this.school);
      }
      @Override
      public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.name=new StringBuffer((String)in.readObject()).reverse().toString();
        this.age=in.readInt();
        this.school=(School)in.readObject();
      }
    
    
    
    }
    class School implements Externalizable{
      private String name;
      public School() {
        System.out.println("School无参构造器");
      }
      //省略有参constructor、setter、getter、toString
    
      @Override
      public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(new StringBuffer(this.name).reverse().toString());
      }
    
      @Override
      public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.name=new StringBuffer((String)in.readObject()).reverse().toString();
      }
    
    
    }
    
    public static void main(String[] args) throws Exception {
      Student s1=new Student("tom",20,new School("xh"));
      System.out.println(s1);
      ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
      oos.writeObject(s1);
      oos.close();
    
      ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
      Student s2=(Student)ois.readObject();
      System.out.println(s2);
      ois.close();
    }
    
    输出:
    Student [name=tom, age=20, school=School [name=xh]]
    Student无参构造器
    School无参构造器
    Student [name=tom, age=20, school=School [name=xh]]
    
    
    

    部分属性序列化

    使用transient关键字

    被transient关键字修饰的属性,在对象序列化时不会序列化,而且反序列化得到的该属性值是默认值

    public class Student implements Serializable{
      private static final long serialVersionUID = 1L;
    
      private String name;
      private transient int age;
      //省略constructor、setter、getter、toString
    }
    public static void main(String[] args) throws Exception{
      Student s=new Student("tom",20);
      System.out.println(s);
      ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
      oos.writeObject(s);
      oos.close();
    
      ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
      Student s2=(Student)ois.readObject();
      System.out.println(s2);
      ois.close();
    }
    输出:
    Student [name=tom, age=20]
    Student [name=tom, age=0]
    

    自定义属性序列化

    • 可以实现Externalizable接口并在序列化方法writeExternal中序列化需要的属性
    • 可以实现Serializable接口,并自己定义
    private void writeObject(java.io.ObjectOutputStream out) throws IOException;
    private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException;
    private void readObjectNoData() throws ObjectStreamException;
    

    writeObject方法序列化需要的属性

    public class Student implements Serializable{
      private static final long serialVersionUID = 1L;
    
      private String name;
      private int age;
      //省略constructor、setter、getter、toString
      private void writeObject(ObjectOutputStream out) throws IOException{
        out.writeObject(this.name);
      }
      private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{
        this.name=(String)in.readObject();
      }
    }
    
    public static void main(String[] args) throws Exception{
      Student s=new Student("tom",20);
      System.out.println(s);
      ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
      oos.writeObject(s);
      oos.close();
    
      ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
      Student s2=(Student)ois.readObject();
      System.out.println(s2);
      ois.close();
    }
    输出:
    Student [name=tom, age=20]
    Student [name=tom, age=0]
    

    序列化对象的static属性

    在对象进行序列化时,被static修饰的属性并不会进行序列化

    public class Student implements Serializable{
      private static final long serialVersionUID = 1L;
    
      private String name;
      public static int age;
      //省略constructor、setter、getter、toString
    }
    
    public static void main(String[] args) throws Exception{
      Student s=new Student("tom");
      Student.age=20;
      System.out.println(s);
      ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
      oos.writeObject(s);
      oos.close();
    
      Student.age=30;
      ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
      Student s2=(Student)ois.readObject();
      System.out.println(s2);
      ois.close();
    }
    输出:
    Student [name=tom,age=20]
    Student [name=tom,age=30]
    

    可以看到Student的static属性age并没有被序列化输出

    实现Serializable的类需要提供一个serialVersionUID

    serialVersionUID是用于确定版本信息的,如果不指定JVM会根据类信息自动生成一个,JVM会根据两个serialVersionUID判断是否是同一个类,如果serialVersionUID不一致,会抛出InvalidClassException异常

    一般建议显式指定serialVersionUID,如果类中添加了新的属性,而想进行向下兼容的话,可以不改变serialVersionUID,那么反序列化后新添加的属性就是默认值

    如果删除了类的属性,就需要修改serialVersionUID

    public class Student implements Serializable{
      private static final long serialVersionUID = 1L;
    
      private String name;
      private int age;
      //省略constructor、setter、getter、toString
    }
    
    //把对象写出去
    @Test
    public void test4() throws IOException {
      Student s=new Student("tom",20);
      System.out.println(s);
      ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
      oos.writeObject(s);
      oos.close();
    }
    
    //删除Student的age属性,并修改serialVersionUID
    public class Student implements Serializable{
      private static final long serialVersionUID = 2L;
    
      private String name;
      //省略constructor、setter、getter、toString
    }
    
    //读取对象
    public static void main(String[] args) throws Exception{
      Student s=new Student("tom");
      ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:/student.txt"));
      Student s2=(Student)ois.readObject();
      System.out.println(s2);
      ois.close();
    }
    输出:
    Exception in thread "main" java.io.InvalidClassException: com.moyuduo.analyze.Student; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
    
  • 相关阅读:
    hdu 5224 Tom and paper 水题
    2015 UESTC 搜索专题N题 韩爷的梦 hash
    2015 UESTC 搜索专题M题 Palindromic String 马拉车算法
    2015 UESTC 搜索专题K题 秋实大哥の恋爱物语 kmp
    2015 UESTC 搜索专题J题 全都是秋实大哥 kmp
    2015 UESTC 搜索专题F题 Eight Puzzle 爆搜
    2015 UESTC 搜索专题E题 吴队长征婚 爆搜
    2015 UESTC 搜索专题D题 基爷的中位数 二分
    2015 UESTC 搜索专题C题 基爷与加法等式 爆搜DFS
    2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索
  • 原文地址:https://www.cnblogs.com/moyuduo/p/12676987.html
Copyright © 2011-2022 走看看