美文网首页
浩哥带你学习JDK1.1源码——第3天

浩哥带你学习JDK1.1源码——第3天

作者: Jack魏 | 来源:发表于2022-05-01 10:38 被阅读0次

JDK1.1源码学习之Serializable源码解析

JDK1.1源码学习之Serializable源码解析

1. Serializable接口结构和统计

还记得之前我们说math包下面的BigDecimal类好欺负吧,
于是我们看来一下源码:
可以看到他继承自Number类(这里省略里面的内容,只看继承)。

public class BigDecimal extends Number {
}

而Number类又实现Serializable接口,于是乎我们就先来分析一下这个接口吧。

public abstract class Number implements java.io.Serializable {
}
BigDecimal架构图

Serializable接口统计结果(IDEA Statistic插件统计)如下:

文件名 大小 总行数 源代码行数 注释行数 空行数
Serializable.java 3.58 KB 79 3 72 4
Statistic统计Serializable源码信息

2. Serializable接口源码翻译

/*
 * @(#)Serializable.java    1.8 2001/12/12
 *
 * 版权所有 2002年 Sun Microsystems,Inc.保留所有权利。
 * SUN 所有者/机密。使用受许可条款约束。
 */

package java.io;

/**
 * 类的序列化由 java.io.Serializable 接口来标识。
 * 没有实现此接口的类是无法序列化或反序列化的。
 * 可序列化的子类也是可以序列化的。
 * 序列化接口没有方法或字段,只是用于标识可序列化。
 * 
 * 为了使不可序列化类的子类允许序列化并且负责保存和恢复超类的公共、受保护和(若可访问)包字段的状态。
 * 只有当它扩展的类具有可访问的无参构造函数来初始化类的状态时,子类才可以实现上面的功能。
 * 在这种情况下,声明一个类 Serializable 是错误的。这会在运行时检测到错误。
 * 
 * 在反序列化过程中,不可序列化类的字段将使用类的公共或受保护的无参数构造函数进行初始化。
 * 可序列化的子类必须可以访问无参数构造函数。可序列化子类的字段将从流中恢复。
 *
 * 在遍历时,可能会遇到不支持 Serializable 接口的对象。此时,会抛出 NotSerializableException 异常,并识别不可序列化对象的类。
 *
 * 在序列化和反序列化过程中需要特殊处理的类必须实现具有这些签名的特殊方法:
 *
 * private void writeObject(java.io.ObjectOutputStream out)
 *     throws IOException
 * private void readObject(java.io.ObjectInputStream in)
 *     throws IOException, ClassNotFoundException;

 * writeObject 方法负责为其特定类写入对象的状态,以便相应的 readObject 方法可以恢复它。
 * 可以通过调用 out.defaultWriteObject 来保存 Object 字段的默认机制。该方法不需要关注属于其超类或子类的状态。
 * 可通过使用 writeObject 方法或使用 DataOutput 支持的原始数据类型的方法将各个字段写入 ObjectOutputStream 来保存对象的状态。

 * readObject 方法负责从流中读取并恢复类字段。它可以调用 in.defaultReadObject 来恢复对象的非静态和非瞬态字段的默认机制。
 * defaultReadObject 方法使用流中的信息将保存在流中的对象的字段分配给当前对象中相应命名的字段。
 * 这可以处理类已经演变为添加新字段的情况。该方法不需要关注属于其超类或子类的状态。
 * 通过使用 writeObject 方法或使用 DataOutput 支持的原始数据类型的方法将各个字段写入 ObjectOutputStream 来保存对象的状态。
 *
 * @author  unascribed(名可名,非常名)
 * @version 1.8, 2001/12/12
 * @see ObjectOutputStream
 * @see ObjectInputStream
 * @see ObjectOutput
 * @see ObjectInput
 * @see Externalizable
 * @since   JDK1.1
 */
public interface Serializable {
}

3. Serializable接口说明

可以看到有效代码也就3行,却写了72行注释,对这个类描述的比较详细了。这里就不赘述上面翻译的内容了,大体就是说实现了这个类就可以序列化了,包括其子类。
在翻译的时候遇到了一个比较费解的地方,就是作者那一栏:unascribed
网上查了一下翻译是:未经描述、未归因
于是又上网百度了一下
作者:unascribed你知道什么意思么?
在java源码中看到这个单词unascribed
Java源码中的 Author: unascribed

表面上意思是这个类不知道作者是谁。但笔者认为不是不知道归属于谁,而是sun公司把它当做是免费的贡献于大众的一个东西,不属于任何人,也属于任何人。这就是开源的意义。
开源软件的出现为个人或小团队开启了大门,他们将自己赤身裸体的暴露出来,整个开源的社会体系中没有门槛,拥有的只有展现自我的激情,充斥着春秋战国时代的理论纷争,新的战场人人可以参与,胜败由自己决定 。
作者:刀客迪克 https://www.bilibili.com/read/cv12550424 出处:bilibili

很中意最后一个作者做出的解释,又加以自己的理解就为其做释:
名可名,非常名:可以言表的都是最肤浅的,所以一切尽在不言中。
其他名人对此的理解

(林语堂) 可以说出来的道,便不是经常不变的道;可以叫的出来的名,便不是经常不变的名。
(陈鼓应) (同上) 可以用言辞表达的道,就不是常道;可以说的出来的名,就不是常名。
(释德清) 真常之道,本无相无名,不可言说。凡可言者,则非真常之道矣,故非常道。

试想一下,宇宙混沌之初万物皆为无名,人类为了便于记忆事物于是就开始起名,一旦事物有了名字就是容易改变了,比如古代对时间称为时辰、白昼、黑夜,现在虽然在用也不是一成不变。

3.1 序列化

好了我们回到主题,那么这个序列化又是什么意思呢?
我们知道所有的类实例化之后都是存在本地内存里面的,
但是处于网络的时代我们大部分的需求是将类的状态进行传递共享的(就是你本地new出来一个类对象,想将里面的属性值一起通过网络或其他形式传给另一台服务器进行处理)。
这个时候就需要序列化(将内存里面的对象以流的形式存储到文件或二进制流)了,而另一台服务器的工作就是反序列化(从文件或二进制流中读取数据流实例化到内存中)。
于是为了实现上面的功能,Java就定义了一个Serializable接口来标识哪些类对象可以用来序列化(状态可传输、保留)。
这里传输是用二进制流的形式,所以就要用到ObjectOutputStreamObjectInputStream,看字面意思就知道是一个写入一个读出。输出到文件可以是任意后缀名,但是官方建议使用.ser后缀。
示意图如下,这里以文件为例,也可以存到数据库等:

序列化与反序列化示意图

比如,我本地有一个User类,new出来的实例对象属性有名字:Jack、年龄:18;一旦电脑关机这个对象就被销毁了,因为new出来的都是在内存中。这时候我希望保留到自己的磁盘或者传输到另一台服务器上,让服务器知道我new出来的属性值(状态),如果是你,你如何解决这个问题呢?

4. Serializable接口最佳实践

下面是最简单例子,如果想查看更多例子请参考文档:第3天(Serializable官方源码解析汇总)

4.1 User类

/*
 * 版权所有(c) Jack魏 2022 - 2022
 */

package jack.io.jack;

import java.io.*;

/**
 * @author Jack魏
 * @version 1.0 2022-04-20 21:05
 */
public class User implements Serializable {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

4.2 测试类

package jack.io;

import jack.io.jack.User;

import java.io.*;

/**
 * @author Jack魏
 * @version 1.0 2022-04-20 00:01
 */
public class SerializableTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        User user = new User();
        user.setName("Jack魏");
        user.setAge(18);
        // 注意这里的目录,否则系统找不到指定的路径。
        String fileName = "E:\\code\\tmp\\user.ser";

        // 序列化
        FileOutputStream fos = new FileOutputStream(fileName);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(user);
        fos.close();

        // 反序列化
        FileInputStream fis = new FileInputStream(fileName);
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object obj = ois.readObject();
        ois.close();
        System.out.println(obj);
    }
}

生成的序列化文件如下(其实就是二进制文件):


User类序列化文件

5. Serializable接口总结

  1. 需要序列化的类必须实现Serializable接口,否则会报错(NotSerializableException)。
  2. 类名、变量(基本数据类型、数组、引用类型)都会被序列化。
  3. 方法、类变量、使用transient修饰变量将不被序列化。
  4. 序列化对象的引用类型成员变量,必须是可序列化的,否则会报错(NotSerializableException)。
  5. 当通过文件、网络来读取序列化对象,必须按照实际写入的顺序读取。
  6. 单例类序列化时,需重写readResolve()方法,否则会破坏单例原则。
  7. 同一对象被多次序列化时,只会对第一次序列化,之后都只是保存序列化编号,不会再次序列化。
  8. 建议加上serialVersionUID ,方便以后项目升级。
  9. 反序列化时必须有对应的类文件,否则会报类找不到错误(ClassNotFoundException)。

相关文章

  • OC对象之旅 weak弱引用实现分析

    Runtime学习 -- weak应用源码学习 Runtime源码分析,带你了解OC实现过程。其中参考了大量的大神...

  • 初中那些事儿(一)

    绯闻 “听说你喜欢浩哥。” “谁?!” “浩哥。” “浩哥是谁?!” 当我知道我喜欢浩哥时,非...

  • 2017-06-12

    #2875―凯―浩哥晚姐橙子学院码字岛第8篇作业#

  • 亲子日记—16

    今天在给姐姐和浩哥读亲子日记的时候,浩哥问我:妈妈,为什么叫我浩哥?我不是叫浩浩吗?我说:浩浩、大浩、浩哥都是妈妈...

  • 周期

    记得几周前学习了得到李笑来老师关于周期的概念。 #2875―凯―浩哥晚姐橙子学院码字岛第7篇作业#

  • 浩哥!😇️

  • 浩哥

    决定要为浩哥写篇文章的时候,正值浩哥离职在即。浩哥,苏州籍人,星座不详,我猜想应该是狮子星座,并不是无迹可寻,每次...

  • 浩哥

    2016年3月,我第一次知道了现实的残酷。 好朋友杰在酒后把我所有的隐私都告诉了领导,比如我讨厌的制度、开会、霸...

  • 浩哥

    后厨最引人注目的,还要算冷库对面的材料柜!尤其是刚配完货,拉开一排排白织灯的电闸,装满橱柜一层层被整理妥帖的盒子...

  • 浩哥

    望着窗外 只要想起一生中后悔的事 梅花便落满了南山 ~摘自浩哥

网友评论

      本文标题:浩哥带你学习JDK1.1源码——第3天

      本文链接:https://www.haomeiwen.com/subject/rfibsrtx.html