天天看点

【Java】Serializable序列化概念

序列化和反序列化

  • 概念
    • 定义
    • 用途
    • JDK类库Serializable
      • serialVersionUID
      • transient
      • 序列化方法
      • 示例

概念

定义

  • 序列化

将对象转换为字节序列的过程

  • 反序列化

将字符序列转换成对象的过程

用途

  • 将内存中的对象持久化到硬盘中, 并之后能再次从磁盘中读取.

如web服务器中的会话session对象都要存储在内存中, 如果某一时间段session对象过多, 则会导致服务器内存不够用的情况, 这时可以借助序列化暂时将一部分session序列化存储到硬盘中, 等到需要时再取出.

  • 将内存中的对象通过网络进行传输.

前后端的交互中, 后端想要向前端发送一个用户的User类的对象时, 可以使用序列化将对象转换成字符串进行传输. 前端接收到字符串后进行解析, 即可获得对象相应属性的信息.

  • 使用redis存储对象

项目中自己定义的对象不属于redis的数据类型, 无法直接用redis存储, 所以要使用redis存储对象或其他数据类型时需要将对象序列化成字符串后再进行存储

JDK类库Serializable

Serializable是JDK类库中的一个接口, 它用来标记一个类可以被实例化, 内部没有任何需要实现的方法.

java.io.ObjectOutputStream: 对象的输出流

调用它的writeObject(Object obj)方法可以将obj对象序列化, 得到的字节序列写到一个目标输出流中

java.io.ObjectInputStream: 对象的输入流

调用它的readObject()方法可以读取流中的字节序列, 并将其反序列化成为一个对象返回.

serialVersionUID

所有实现了Serializable接口的类都会有的默认的静态变量, 用来标记类的序列化版本号, 用来版本控制.

如果没有显示定义serialVersionUID的时候, java序列化机制会根据Class自动生成一个serialVersionUID, 如果Class文件发生变化, 则serialVersionUID会相应的改变.

  • 可以自认定义, 一般默认版本号为1L
  • 也可以根据包名, 类名, 方法和属性等多个因素计算得出, 生成一个复杂的唯一的哈希字段.

序列化对象时, 序列化的结果里会保存当前对象所在类的serialVersionUID, 反序列化时会检查类中的UID与返序列化对象的UID是否一致, 不一致则不允许序列化. 并抛出异常

可以用idea自动生成

在setting中设置没有serialVersionUID时警告

【Java】Serializable序列化概念

在类名出现警告时可以选择自动生成

【Java】Serializable序列化概念

transient

为了提高效率, 类中某些属性在对象序列化时是没有必要被保存的, 或是需要被忽略的, 这时可以用transient关键字来标记这些属性不被序列化.

被static和transient修饰的属性都不会被序列化.

例如一些流stream, 在反序列化之后可能已经不存在了. 或者需要重新打开, 这个属性就可以用transient标记不被序列化

被标记的transient属性在反序列化的时候会被赋值为默认的初值, 如int赋值0, 对象赋值null等

序列化方法

现有一个Person类实现了Serializable接口

- 该Persson类只实现了Serializable

则直接用Object输入流或输出流的writeObject(Object obj)或readObject()方法直接对Person类的非transient属性进行序列化和反序列化

- 该Person实现了Serializable,并且在类中重新定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out)方法

在序列化和反序列化时会调用类中的readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out)方法.

- 该Person类实现了Externalnalizable接口

则类中必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法, 并通过该方法进行序列化.

示例

Person

class Person implements Serializable {

    String id;
    String name;
    Integer age;

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Person() {
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Person(String id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}
           

Util

/**
 * @author: shuo
 * @date: 2019/05/28
 */
public class JdkSerializableUtil<T>  {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        byte[] bytes;
        Person person = new Person("10", "张三", 17);
        bytes = objectSerialize(person);
        System.out.println(Arrays.toString(bytes));
        person = objectUnSerialize(bytes, person);
        System.out.println(person);
    }

    /**
     * 序列化
     * @param o
     * @return
     * @throws IOException
     */
    public static byte[] objectSerialize(Object o) throws IOException {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(o);
            return byteArrayOutputStream.toByteArray();
    }

    /**
     *  反序列化
     * @param bytes
     * @param t
     * @param <T>
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static<T> T objectUnSerialize(byte[] bytes, T t) throws IOException, ClassNotFoundException {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        return (T)(objectInputStream.readObject());
    }
}
           

测试

public static void main(String[] args) throws IOException, ClassNotFoundException {
        byte[] bytes;
        Person person = new Person("10", "张三", 17);
        bytes = objectSerialize(person);
        System.out.println(Arrays.toString(bytes));
        person = objectUnSerialize(bytes, person);
        System.out.println(person);
    }
           

结果

[-84, -19, 0, 5, 115, 114, 0, 25, 74, 97, 118, 97, 84, 101, 115, 116, 46, 115, 101, 114, 105, 97, 108, 105, 122, 101, 46, 80, 101, 114, 115, 111, 110, -65, -83, 12, -26, -15, 69, 33, -44, 2, 0, 3, 76, 0, 3, 97, 103, 101, 116, 0, 19, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 73, 110, 116, 101, 103, 101, 114, 59, 76, 0, 2, 105, 100, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 76, 0, 4, 110, 97, 109, 101, 113, 0, 126, 0, 2, 120, 112, 115, 114, 0, 17, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 73, 110, 116, 101, 103, 101, 114, 18, -30, -96, -92, -9, -127, -121, 56, 2, 0, 1, 73, 0, 5, 118, 97, 108, 117, 101, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 0, 0, 0, 17, 116, 0, 2, 49, 48, 116, 0, 6, -27, -68, -96, -28, -72, -119]
Person{id='10', name='张三', age=17}