整理了一些Java方面的架构、面试资料(微服务、集群、分布式、中间件等),有需要的小伙伴可以关注公众号【程序员内点事】,无套路自行领取

更多优选

写在前边

最近有个公众号粉丝和我聊了聊他面试的经历,一个刚入坑Java两年的新人,由于疫情原因视频面试,而面试官只问了一个问题:“Java序列化为什么要实现Serializable接口?”,结果他一时语塞面试OVER。说实话听到这个问题,我也有些懵逼,平时忙着研究各种中间件、什么高可用框架,可真要回头对Java基础知识较起真,发现自己的技术债欠的太多,所以和大家一起复习一下Java序列化知识。


什么是Java序列化?

序列化Java中的序列化机制能够将一个实例对象信息写入到一个字节流中(只序列化对象的属性值,而不会去序列化方法),序列化后的对象可用于网络传输,或者持久化到数据库、磁盘中。

反序列化:需要对象的时候,再通过字节流中的信息来重构一个相同的对象。

Java中要使一个类可以序列化,实现java.io.Serializable接口是最简单的。

public class User implements Serializable {

    private static final long serialVersionUID = 1L;
}

那么我们来看看Serializable接口的源码实现,可以看到Serializable接口中并没有方法或字段,这个接口仅仅用于标识可序列化的语义,也就是说它只是用来标识一个对象是否可被序列化。

package java.io;

/**
* @author unascribed
* @see java.io.ObjectOutputStream
* @see java.io.ObjectInputStream
* @see java.io.ObjectOutput
* @see java.io.ObjectInput
* @see java.io.Externalizable
* @since JDK1.1
*/
public interface Serializable {
}

接下来写一个对象信息写入磁盘的例子测试一下:

创建一个User对象,并实现Serializable接口

@Data
public class User implements Serializable { private static final long serialVersionUID = 1L; private String name; private String age;
}

User对象信息写入到磁盘当中

@Slf4j
public class serializeTest { public static void main(String[] args) throws Exception {
User user = new User();
user.setName("fufu");
user.setAge("18"); serialize(user);
log.info("Java序列化前的结果:{} ", user); User duser = deserialize();
log.info("Java反序列化的结果:{} ", duser);
}
/**
* @author xzf
* @description 序列化
* @date 2020/2/22 19:34
*/
private static void serialize(User user) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\111.txt")));
oos.writeObject(user);
oos.close();
}
/**
* @author xzf
* @description 反序列化
* @date 2020/2/22 19:34
*/
private static User deserialize() throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\111.txt")));
return (User) ois.readObject();
}
}
序列化前的结果: User(name=fufu, age=18)
反序列化后的结果: User(name=fufu, age=18)

打开writeObject方法的源码看一下,发现方法中有这么一个逻辑,当要写入的对象是StringArrayEnumSerializable类型的对象则可以正常序列化,否则会抛出NotSerializableException异常。

这就能解释为什么Java序列化一定要实现Serializable接口了。

/**
* Underlying writeObject/writeUnshared implementation.
*/
private void writeObject0(Object obj, boolean unshared)
throws IOException
{
boolean oldMode = bout.setBlockDataMode(false);
depth++;
try {
// 省略号。。。。。。。。。。 // remaining cases
if (obj instanceof String) {
writeString((String) obj, unshared);
} else if (cl.isArray()) {
writeArray(obj, desc, unshared);
} else if (obj instanceof Enum) {
writeEnum((Enum<?>) obj, desc, unshared);
} else if (obj instanceof Serializable) {
writeOrdinaryObject(obj, desc, unshared);
} else {
if (extendedDebugInfo) {
throw new NotSerializableException(
cl.getName() + "\n" + debugInfoStack.toString());
} else {
throw new NotSerializableException(cl.getName());
}
}
} finally {
depth--;
bout.setBlockDataMode(oldMode);
}
}

那么可能会有人疑问,String为啥就不用实现Serializable接口呢?其实String已经内部实现了Serializable,不用我们再显示实现。看看源码就懂了

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[]; /** Cache the hash code for the string */
private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L; ......
}

既然已经实现了Serializable接口,为什么还要显示指定serialVersionUID的值呢?

因为序列化对象时,如果不显示的设置serialVersionUID,Java在序列化时会根据对象属性自动的生成一个serialVersionUID,再进行存储或用作网络传输。

在反序列化时,会根据对象属性自动再生成一个新的serialVersionUID,和序列化时生成的serialVersionUID进行比对,两个serialVersionUID相同则反序列化成功,否则就会抛异常。

而当显示的设置serialVersionUID后,Java在序列化和反序列化对象时,生成的serialVersionUID都为我们设定的serialVersionUID,这样就保证了反序列化的成功。

transient

序列化对象时如果希望哪个属性不被序列化,则用transient关键字修饰即可

@Data
public class User implements Serializable { private transient String name; private String age;
}

可以看到字段name的值没有被保存到磁盘中,一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。

Java序列化前的结果: User(name=fufu, age=18)
Java反序列化的结果:User(name=null, age=18)

一个静态变量不管是否被transient修饰,均不能被序列化。 因为static修饰的属性是属于类,而非对象。

总结

分享了一个很小的知识点,工作再忙也不要忘了温故而知新哦


今天就说这么多,如果本文对您有一点帮助,希望能得到您一个点赞

面试官:Java序列化为什么要实现Serializable接口?我懵了的更多相关文章

  1. 我写了一个java实体类,implements了Serializable接口,然后我如何让serialversionUID自动生成

    写了一个java实体类,implements了Serializable接口,让serialversionUID自动生成方法: 1.点击类旁边的警告符号: 2.选择Add generated seria ...

  2. Java对象为啥要实现Serializable接口

    Serializable接口概述 Serializable是java.io包中定义的.用于实现Java类的序列化操作而提供的一个语义级别的接口.Serializable序列化接口没有任何方法或者字段, ...

  3. Java中的实体类--Serializable接口、transient 关键字

    在java中,实体类是一个非常重要的概念,我们可以在实体类中封装对象.设置其属性和方法等.关于实体类,也经常涉及到适配器模式.装饰者模式等设计模式.那么在实际代码开发中,关于实体类的注意事项有哪些呢? ...

  4. java类为什么要实现Serializable接口

    什么是Serializable接口? 一个对象序列化的接口.一个类只有实现了Serializable接口,它的对象才能被序列化. 什么是序列化? 将对象的状态信息转换为可以存储或传输的形式的过程. 在 ...

  5. java基础 序列化反序列化流 实现Serializable 接口 自动装载序列号到对象文本文件如修改不能反序列化对象文本,除非自定义long型常量 打印流

    package com.swift.baseKnowledge; import java.io.File; import java.io.FileInputStream; import java.io ...

  6. 面试官之问:知道你的接口“QPS”是多少吗?

    前言: 原作:孤独烟.因修改不当之处欢迎指出! 大家好,我是小架架. 今天一大早就起来水文章了.这篇文章我个人感觉虽然含金量不是特别大,估计大家大概5分钟左右就能看完!到底是因为什么呢,因为平时干货文 ...

  7. 面试官问,Redis 是单线程还是多线程?我懵了

    我们平时看到介绍 Redis 的文章,都会说 Redis 是单线程的.但是我们学习的时候,比如 Redis 的 bgsave 命令,它的作用是在后台异步保存当前数据库的数据到磁盘,那既然是异步了,肯定 ...

  8. JAVA 序列化_基础

    JAVA序列化 实现 Serializable 接口的对象,可以序列化为本地文件 简单示例: //序列化类 public class Test implements Serializable { pr ...

  9. Java 序列化Serializable详解

    Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...

随机推荐

  1. MGR监控报警

    一.报警思路 m.conf文件记录配置信息,只需要修改这个文件的内容即可(需要将mysql_stat.sh里面的信息写到这里,进行中) mysql_stat.sh文件作为MGR状态监测脚本,加入定时任 ...

  2. artTemplate--模板使用自定义函数(1)

    案例 因为公司业务需要频繁调用接口,后端返回的都是json树对象,需要有些特殊的方法做大量判断和数据处理,显然目前简单语法已经不能满足业务需要了,需要自己定制一些 方法来处理业务逻辑. 例如后台返回的 ...

  3. JDK的下载及安装教程图解(超详细哦~)

    一.本人电脑系统介绍及JDK下载途径 1.先说明一下我的电脑为win10系统,64位操作系统~ 2.我选择下载的JDK版本为1.8版本.给大家来两个下载渠道,方便大家的下载~ JDK官网:https: ...

  4. oracle的锁种类知识普及

    锁概念基础 数据库是一个多用户使用的共享资源.当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性. 加 ...

  5. 利用Python进行TCP、UDP套接字编程

    参考:http://www.cnblogs.com/whatbeg/p/5155524.html http://www.cnblogs.com/nzyjlr/p/4236287.html

  6. Flink与HanLP集成使用

    自然语言处理是机器学习的一个重要分支,在智能翻译.智能问答.舆情监控.ChatOps等都有很好的应用场景,目前比较好的一个开源实现工具是何晗大神的HanLP,主页(http://hanlp.com/) ...

  7. [Effective Java 读书笔记] 第三章 对所有对象都通用的方法 第八 ---- 九条

    这一章主要讲解Object类中的方法, Object类是所有类的父类,所以它的方法也称得上是所有对象都通用的方法 第八条 覆盖equals时需要遵守的约定 Object中的equals实现,就是直接对 ...

  8. javascript Math对象 常用数字操作方法

    var t='1.2'; parseInt(t) parseFloat(t)//1.2 Number(1.2)//1.2强制转换为数字 2.向上取整,有小数就整数部分加1 js: Math.ceil( ...

  9. C#实现读取IPv6 UDP Socket数据,再发送出去

    C#实现读取IPv6 UDP Socket数据,再发送出去. 不知为何,黑框点一下就停止刷新了,再点一下,就继续刷新了. using System; using System.Collections. ...

  10. Mysql 导入导出备份

    恢复MySQL服务器上面的txt格式文件(需要FILE权限,各数据值之间用"制表符"分隔)   1.导入数据库服务器上的txt文件 mysql>load data infil ...