0

0

Java序列化之Serializable

高洛峰

高洛峰

发布时间:2017-03-18 11:35:49

|

3367人浏览过

|

来源于php中文网

原创

qq图片20161101114531.png

Java的序列化流程如下:

QQ图片20161101114531.png

Java的反序列化流程如下:

QQ图片20161101114531.png

立即学习Java免费学习笔记(深入)”;

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

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,即瞬时关键字。该关键字关闭字段的序列化,这样受保护的信息就不会因为序列化而对外暴露。

Detect GPT
Detect GPT

一个Chrome插件,检测您浏览的页面是否包含人工智能生成的内容

下载

序列化标识ID

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

  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速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

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

相关专题

更多
Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

37

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

37

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

16

2026.01.13

PHP缓存策略教程大全
PHP缓存策略教程大全

本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.13

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

交互式图表和动态图表教程汇总
交互式图表和动态图表教程汇总

本专题整合了交互式图表和动态图表的相关内容,阅读专题下面的文章了解更多详细内容。

45

2026.01.13

nginx配置文件详细教程
nginx配置文件详细教程

本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

9

2026.01.13

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.5万人学习

C# 教程
C# 教程

共94课时 | 6.7万人学习

Java 教程
Java 教程

共578课时 | 46.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号