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
    
  • 相关阅读:
    delphi xe10.4新功能介绍
    python tornado 增加数据库连接池
    sql server 自增型字段 在有数据的情况下 修改 标识种子
    c++定时重启某个windows程序
    mssql server 查看作业中执行了哪些脚本
    mssql server 13位时间戳互转
    delphi 13位时间戳互转
    博客开通啦
    java获取当前应用的运行信息(内存,线程,运行时间,状态等)
    java使用websocket,并且获取HttpSession,源码分析
  • 原文地址:https://www.cnblogs.com/moyuduo/p/12676987.html
Copyright © 2011-2022 走看看