• 【技术累积】【点】【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。该存储规则极大的节省了存储空间。

    参考文章

  • 相关阅读:
    hdu 1394 Minimum Inversion Number(线段树之 单点更新求逆序数)
    spring问题排查-调低日志等级
    android中的返回键与Activity
    poj 1273 Drainage Ditches
    zoj Reactor Cooling
    Android build-tools升级到23.0.0_rc1无法解决编译后的问题
    HDU ACM 2845 Beans->动态规划
    HTML中心在页面上弹出自定义表单层(实现可能拖累)
    欧氏定理最大公约数和最小公倍数
    token session cookie
  • 原文地址:https://www.cnblogs.com/andy1202go/p/9761012.html
Copyright © 2020-2023  润新知