Java序列化之Serializable

轻伟小哥_4985

轻伟小哥_4985

2017-03-18

3447人浏览

原创

qq图片20161101114531.png

Java的序列化流程如下:

QQ图片20161101114531.png

Java的反序列化流程如下:

QQ图片20161101114531.png

注意:并不是所有类都需要进行序列化,主要原因有两个

1)安全问题。Java中有的类属于敏感类,此类的对象数据不便对外公开,而序列化的对象数据很容易进行破解,无法保证其数据的安全性,因此一般这种类型的对象不会进行序列化。

2)资源问题。可以使用序列化字节流创建对象,而且这种创建时不受限制的,有时过多地创建对象会造成很大的资源问题,因此此类对象也不适宜进行序列化。

Serializable

Serializable是Java提供的一个序列化接口,它是一个空接口,专门为对象提供标准的序列化跟反序列化操作。

序列化过程:

Person p = new Person("name","id");
        File file = new File("cache.txt");
        FileOutputStream output = new FileOutputStream(file);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(output);
        objectOutputStream.writeObject(p);
        output.close();
        objectOutputStream.close();

反序列化过程:

File file = new File("cache.txt");
        FileInputStream input= new FileInputStream(file);
        ObjectInputStream objectInputStream = new ObjectInputStream(input);
        Person p = (Person)objectInputStream.readObject();
        System.out.println(p.getName()+"---"+p.getId());
        input.close();
        objectInputStream.close();

需要序列化的类成员

    对象序列化时并不是所有成员都要转换成二进制的字节序列,因为为了节省存储或传输空间以及提高序列化效率,有些不必要的成员是无需序列化的。其中包括:

  静态变量。因为静态变量属于类的属性,并不属于某个具体实例,因此在序列化的时候无须进行序列化,反序列化时,可以直接获取类的静态成员引用。

  方法。方法只是一系列的操作集合,方法不会依赖对象,不会因为对象的不同,而操作不同,反序列化时,也可以从类中直接获取方法信息。

继承关系的序列化

父类实现Serializable时,子类被序列化,父类也会被序列化。

父类没有实现Serializable时,子类被序列化,父类不会被序列化

引用关系的序列化

    如果对一个实现了Serializable的类进行序列化操作,则同时对它的引用类进行序列化操作。如果引用类没有实现Serializable接口,JVM会抛出java.io.NotSerializableExeception.

class Person implements Serializable{
    private String name;
    private Tool tool = new Tool();
}

class Tool implements Serializable{
    
}

 此时对Person类进行序列化操作,则会同时对Tool类进行序列化操作。若Tool类没有实现Serializable接口,则会抛出异常。

保护敏感数据:

  一个类加上序列化标识后,该类对象的所有属性信息将被序列化,然后进行本地存储或网络传输。然后有时对象中的某些字段属于敏感信息,不应暴露出来。如果对其也进行序列化,容易被破解,从而   造成安全隐患,例如常见的密码字段。

  Java提供一个关键字transient,即瞬时关键字。该关键字关闭字段的序列化,这样受保护的信息就不会因为序列化而对外暴露。

序列化标识ID

Java注释规范Skills
Java注释规范Skills

当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。

下载

  试想一下这样的情景:两端进行网络传输序列化对象,由于某种原因,导致两端使用的类的版本不同,假设接收方的类被删除了几个字段。当发送发将对象的序列化字节流发送到接收方时,由于接收方 的类少了几个字段,而无法解析。  

  Java要求实现序列化接口的类都必须声明一个serialVersionUID静态属性,如果没有该属性JVM也会自动声明该属性,并为该属性赋值(当类发生改变时会赋予不同的值)。该属性的值是唯一的,用于 标识不同的序列化类。只有类的序列化标识完全相同,Java才会进行反序列化工作,这就是序列化标识的作用。

  对于前面提到的情景,假设没有手动声明serialVersionUID,则JVM对发送方跟接收方使用的类中的serialVersionUID赋予不同的值,则反序列化失败。当手动给serialVersionUID赋值时,即使类的字 段发生改变,也能够反序列化成功。

自定义序列化策略

  定制序列化策略     

      Java提供了一套有效的机制,允许在序列化和反序列化时,使用定制的方法进行相应的处理。当传输双方协定好序列化策略后,只需要在需要传输的序列化类中添加一组方法来实现这组策略,在序列化时会自动调用这些规定好的方法进行序列化和反序列化。方法如下:

     1)private void writeObject(ObjectOutputSteam out) throws IOException  

  在方法的内部有重要的代码:out.defaultWriteObject()    //将对象数据以默认方式写入到输出流中

     2)private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException

  同样的,此方法内部也有相似代码:in.defaultReadObject();  //以默认方式从输入流中恢复对象

这两个方法的作用分别是将特定的对象写入到输出流中以及从输入流中恢复特定的对象,通过这两个方法,用户即可实现自定义的序列化。当在实现Serializable接口的类中写了上面两个方法之后,序列化或反序列化该类时则会通过反射来调用这两个方法,从而实现自定义序列化。

限制序列化对象的数量     

我们看下面的单例模式:

public class Singleton implements Serializable {

    private volatile static Singleton mInstance;
    private Singleton() {
    }

    public static Singleton getInstance() {
        if (mInstance == null) {
            synchronized (Singleton.class) {
                if (mInstance == null) {
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }
}

此时通过反序列化获取实例,则单例模式会失效。那该如何解决这个问题呢?

  Java有一种机制,可以让我们在序列化和反序列化时,可以根据自己的需要,写入或读取指定的实例。使用这种机制,需要在实现Serializable接口的类中添加两个方法:

    private Object readResolve()   //如果用户在序列化类中添加了该方法,则在进行反序列化时,使用该方法返回的对象,作为反序列化对象。

    private Object writeReplace()   //如果用户在序列化类中添加了该方法,则在进行序列化时,序列化该类返回的对象。

再看使用了该机制的单例模式:

public class Singleton implements Serializable {

    private volatile static Singleton mInstance;
    private Singleton() {
    }

    public static Singleton getInstance() {
        if (mInstance == null) {
            synchronized (Singleton.class) {
                if (mInstance == null) {
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }

    private Object readResolve() {
        return getInstance();
    }

    private Object writeReplace() {
        return getInstance();
    }
}

 此时的通过反序列化得到的对象也是同一个,即单例模式依然有效!

相关文章:

Java序列化Serializable和Externalizable区别的示例代码

java 序列化对象 serializable 读写数据的实例

php—Serializable接口

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

java

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

2026.10.28

40

16

Vite 如何搭配 Vue.js
Vite 如何搭配 Vue.js

Vite搭配Vue.js专题汇集创建Vue 3项目、配置开发环境、路径别名、Vue插件、代理、多环境构建与调试的已审核文章,帮助读者完成从初始化到日常开发的配置。

2026.10.28

20

15

Vite 项目目录怎么看
Vite 项目目录怎么看

Vite项目目录专题汇集入口文件、src源码、public静态资源、路径别名、项目根目录和构建输出目录相关的已审核文章,帮助读者理解各文件夹的用途与引用方式。

2026.10.28

40

10

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

2026.10.22

120

11

Gradle Wrapper配置教程
Gradle Wrapper配置教程

本专题介绍Gradle Wrapper的基本作用,涵盖文件组成、生成方法、版本配置和任务调用,帮助你理解项目如何使用指定的Gradle版本,减少不同开发环境带来的构建差异。

2026.10.22

80

10

Golangci-lint检查器使用教程
Golangci-lint检查器使用教程

本专题整理Golangci-lint常用Linters的用途与配置方法,覆盖错误处理、无效代码、安全、复杂度、命名和依赖检查,帮助项目合理选规则。

2026.10.22

80

15

Gradle怎么构建Java项目
Gradle怎么构建Java项目

本专题介绍Gradle Java项目构建方法,涵盖Java插件配置、依赖声明、源码编译、测试执行和打包检查,帮助你理解各阶段的任务关系,逐步完成项目构建。

2026.10.22

40

10

PHP时间戳漏洞修复教程
PHP时间戳漏洞修复教程

本专题汇总PHP常见时间戳漏洞,包括2038年溢出、时区漂移、时间戳伪造、重放攻击、时间盲注与日志审计失效等,并给出升级64位环境、使用 DateTimeImmutable、统一UTC、严格超时校验、预处理绑定、hash_equals 比对等修复方案,帮助开发者快速排查和加固时间相关代码。

2026.10.22

80

25

Golangci-lint配置文件与规则设置
Golangci-lint配置文件与规则设置

本专题聚焦Golangci-lint YAML配置文件,讲清运行参数、规则启停、目录排除、问题过滤及严重级别设置,便于团队统一检查标准。

2026.10.22

40

15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习