【技术累积】【点】【java】【21】序列化二三事

基础概念

  • 把对象等转为二进制进行传输的是序列化,反之为反序列化;
  • 应用场景一般为读写文件,传输数据/接口调用;

Externalizable和Serializable

java的序列化方式有两种;

Serializable是常用的方法,实现方法为

class User implements Serializable {
        private static final long serialVersionUID = -3226152074589523662L;
       ...
    }

实现接口,并且最好有序列化ID;

Externalizable是Serializable的子类,但不会自动化序列化,需要调用方法实现序列化;

idea自动生成序列化ID

打开设置中的检测,然后每次有需要序列化的,生成一个Long型即可

Intellij idea用快捷键自动生成序列化id

序列化ID也可以是自定义的,比如简单的1L,只要调用方和被调用方约定一致即可;

transient关键字

  • transient修饰的变量,不会被序列化;
  • 静态变量一定不会被序列化(类的属性而不是对象的属性值)
  • 一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问;
  • transient关键字只能修饰变量,而不能修饰方法和类;
  • 使用Externalizable可以序列化transient修饰的变量
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.testng.annotations.Test;

import java.io.*;

@Slf4j
public class TestTransient {

//    private static final long serialVersionUID = 8204877978271765366L;

    @Test
    public void testTransi(){
        User user = new User("andy","123456");
        log.info("Before serializable,user={}",user.toString());
        try {
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D:/user.txt"));
            os.writeObject(user);
            os.flush();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {

            ObjectInputStream is = new ObjectInputStream(new FileInputStream("D:/user.txt"));
            user = (User) is.readObject();
            is.close();
            log.info("After serializable,username={},pwd={}",user.getUsername(),user.getPassword());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    @Setter
    @Getter
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    static class User implements Serializable {
        private static final long serialVersionUID = -3226152074589523662L;
        String username;
        transient String password;
    }
}

还需要注意的几个问题

  • 虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致
  • 要想将父类对象也序列化,就需要让父类也实现Serializable 接口。如果父类不实现的话的,就需要有默认的无参的构造函数
  • 可以尝试使用序列化实现加密控制等(Override),参考RMI技术
  • 注意往一个文件中多次写入同一个对象的情况

Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,上面增加的 5 字节的存储空间就是新增引用和一些控制信息的空间。反序列化时,恢复引用关系,使得清单 3 中的 t1 和 t2 指向唯一的对象,二者相等,输出 true。该存储规则极大的节省了存储空间。

参考文章

posted @ 2018-10-09 16:20  韧还  阅读(231)  评论(0编辑  收藏  举报