关于java:序列化与反序列化

简述

序列化就是将某个对象转换成特定的数据格式,反序列化即序列化的返操作。个别将序列化后的数据通过网络传输或者保留到数据库。

java的序列化操作

在Java中,若要将一个对象可序列化则要实现 Serializable接口。且尽可能标记属性serialVersionUID(前面Test将阐明为什么要标记此属性),个别IDEA会主动生成。

  • 如我有一列

    class Order implements Serializable {
      
      private static final long serialVersionUID = 1L;
      
      private String orderNo;
      private int amount;
      
      //结构
      //getter setter...
      
      @Override
      public String toString() {
         //所有属性
      }
    }

当初将利用java.io包下的ObjectOutputStreamFileOutputStream 来演示如何将Order对象序列化到文件里保存起来

public class SerializableTest {

    public final static String PATH = "/tmp/order.txt";

    @Test
    public void test_serializable() throws IOException {
        Order o = new Order("abc", 1299, new Address("安徽"), new Person("Savey"));
        try ( FileOutputStream fstream =  new FileOutputStream(PATH);
              ObjectOutputStream objectOutputStream = new ObjectOutputStream(fstream)
        ) {
            
            //接管一个对象、并将对象转为字节流
            objectOutputStream.writeObject(o);
            //刷新到输入fstream
            objectOutputStream.flush();
        }
    }
}

此时 Order对象曾经被序列化到 /tmp/order.txt文件里。

java的反序列化操作

如上回说到Order曾经被咱们保留到指定文件,此时咱们想读取数据则这样解决

    @Test
    public void test_covert_object() throws IOException, ClassNotFoundException {
        try (FileInputStream fileInputStream = new FileInputStream(PATH);
             ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)
        ) {
            
            //从一个输出流读取数据转为对象,这里加个强转为Order
            Order o = (Order)objectInputStream.readObject();

            System.out.println(o);
        }
    }

此时咱们利用了几个重要的对象帮忙咱们序列和反序列操作

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;

注意事项

serialVersionUID

如果我在序列化之前的 Order对象是这样的

class Order implements Serializable {

    private static final long serialVersionUID = 1L;
    
}

在反序列化之后serialVersionUID变了

class Order implements Serializable {

    private static final long serialVersionUID = 2L;
    
}

那么不好意思,会报错,如下:

java.io.InvalidClassException: Order; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

序列化对象里有其余自定义对象

比方我在Order里加了一个Person对象

class Order implements Serializable {
    private static final long serialVersionUID = 1L;
    
    //其余属性
    
     private Person person;
    
    //getter setter construct toString
    
}


class Person implements Serializable {

    private static final long serialVersionUID = 2L;
}

如果Person没有实现Serializable接口也会出错,如下:

java.io.NotSerializableException: Person

But 你能够批改Person的申明形式

private transient Person person;

用关键字transient来润饰您不想序列化的属性!在ArrayList源码里 是不是也见过这个关键字呢???

/**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

自定义序列化

不错,您还能够自定义你要序列化的内容,java很优雅的为咱们提供了两个办法重写序列化的办法

private void writeObject(ObjectOutputStream oos)

private void readObject(ObjectInputStream ois)

这两个办法见名思意,一个写入、一个读取。如上回说到一个属性被要害写transient润饰了,但我还想将它序列化下~

class Order implements Serializable {
    
    //其余属性
    private transient Person person;
    

    private void writeObject(ObjectOutputStream oos)
            throws IOException {
        oos.defaultWriteObject();
        
        //自定义写入Person这个对象、只管你是 transient润饰了!!
        oos.writeObject(person);
    }
        
        

    private void readObject(ObjectInputStream ois)
            throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        
        //读取强行转成Person对象
        Person person = (Person) ois.readObject();
        this.setPerson(person);
    }        


    //getter setter construct
    
}

下面代码演示了如果自定义序列化和反序列化,如果你有多个属性要自定义操作,请留神的写入的程序,和读取的程序要一一对应,不然会出错的哦!

java.lang.ClassCastException: XXX cannot be cast to XXX

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理