Java基础巩固-关于Java序列化和反序列化

简介: 题外话:从事IT要学习的东西太多了,有时候会比较浮躁,因为要学的东西太多但又无从下手,甚至有很多基础都还没有深入学习,这个时候应当静下心来,正所谓不忘初心,方能始终,之前一直听说过序列化,但也没有去深入一点点的了解过,这个时候,就当好好巩固下了~java序列化常被称为持久化,将其写入磁盘中。

题外话:
从事IT要学习的东西太多了,有时候会比较浮躁,因为要学的东西太多但又无从下手,甚至有很多基础都还没有深入学习,这个时候应当静下心来,正所谓不忘初心,方能始终,之前一直听说过序列化,但也没有去深入一点点的了解过,这个时候,就当好好巩固下了~

java序列化

常被称为持久化,将其写入磁盘中。
对于一个存在于jvm的对象来说,内部的状态保存在内存中,当jvm停止时这些状态就丢失了,但有些时候对象的内部是需要持久保存的,对象序列化机制(object serialization)是Java语言内建的一种对象持久化方式,可以很容易的在JVM中的活动对象和字节数组(流)之间进行转换,该机制中对象可以表示为字节序列,该字节序列包括该对象的数据,有关对象的类型的信息和存储在对象中数据的类型。

数据序列化就是将对象或者数据结构转化成特定的格式,使其可在网络中传输,或者可存储在内存或者文件中。反序列化则是相反的操作,将对象从序列化数据中还原出来。而对象序列化后的数据格式可以是二进制,可以是XML,也可以是JSON等任何格式。

【整个过程在jvm独立的,在一个平台上序列化的对象可以在另外的平台反序列化】

java类序列化的条件:

1.该类必须实现 java.io.Serializable接口。
2.该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。如果你想知道一个 Java 标准类是否是可序列化的,请查看该类的文档。检验一个类的实例是否能序列化十分简单, 只需要查看该类有没有实现 java.io.Serializable接口。

为什么序列化

1.将结构化的对象变为无结构的字节流,存储对象在存储介质中,方便下次使用可以快捷获取,便于数据传输。
2.序列化的过程通俗讲,就是一个“freeze”的过程,它将一个对象freeze住,然后进行存储,等到再次需要的时候,再将这个对象de-freeze就可以立即使用。

jdk内置序列化

java对序列化提供了很好的支持,当一个对象实现了Serilizable接口,这个对象就可以被序列化,我们不关心其内在的原理,只需要了解这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。可以说Serilizable只是一个标识,实际的序列化和反序列化工作是通过java.io.ObjectOuputStream和java.io.ObjectInputStream来完成的。ObjectOutputStream的writeObject方法可以把一个Java对象写入到流中,ObjectInputStream的readObject方法可以从流中读取一个Java对象。

transient关键字

在实际开发过程中可能遇到说一个对象中的属性有些需要序列化有些则不用,比如说一个用户有些敏感信息(密码,银行卡号),为了安全考虑不需要在网络操作中被传输。
这种时候使用transient可以使对应的属性不被写入磁盘持久化。换句话说,这个对象的生命周期仅存在调用者的内存中而不被持久化在硬盘中或者网络传输。

//使用例子
package serializable;
import java.io.*;

public class TransientTest implements Serializable{
    static class UserInfo implements Serializable {
        private String name; //此处加static反序列化后仍能取到是因为static修饰的变量存在jvm内存中
        private transient String psw;//transient 只能修饰变量(属性)
        public UserInfo(String name, String psw) {
            this.name = name;
            this.psw = psw;
        }

        public String toString() {
            return "name=" + name + ", psw=" + psw;
        }
    }

    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("张三", "123456");
        System.out.println(userInfo);
        try {
            // 序列化将对象属性写入到UserInfo.txt文件中,被设置为transient的属性没有被序列
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt"));
            o.writeObject(userInfo);
            o.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            // 重新读取序列化内容
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt"));
            UserInfo readUserInfo = (UserInfo) in.readObject();
            System.out.println(readUserInfo.toString()); //修饰transient关键字的属性打印为null
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
img_eb66e8be8f833af53bbb4664519b4420.png
测试

Externalizable接口

在java中,对象的序列化可以通过两种接口实现,除了Serilizable接口,还有就是Externalizable接口。
1.若实现Serializable,则所有序列化将会自动执行。
2.若实现Externalizable,序列化的过程需手动执行,需要在writeExternal方法中进行手工指定所要序列化的变量,与是否被transient修饰无关。

import java.io.*;
/**
 * Created by LJW on 2018/5/28.
 * Externalizable接口测试
 */
public class TestExternalizable implements Externalizable {
    private transient String content = "就算被transient修饰,但如果实现的是Externalizable接口,我还是可能被序列化";
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    }

    public static void main(String[] args) throws Exception {
        TestExternalizable et = new TestExternalizable();
        //将TestExternalizable序列化到test.txt文件中
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
                new File("test.txt")));
        out.writeObject(et);
        //反序列化test.txt中的信息
        ObjectInput in = new ObjectInputStream(new FileInputStream(new File(
                "test.txt")));
        et = (TestExternalizable) in.readObject();
        System.out.println(et.content);//成功打印content内容而不是null,说明反序列化有取到被transient修饰的变量属性
        out.close();
        in.close();
    }
}

serialVersionUID

在查看jdk源码的时候,经常看到这种代码

private static final long serialVersionUID = 2877471301981509474L; //xxxL 

一个类如果使用了java.io.Serializable接口,在序列化到文件时会自动生成一个serialVersionUID,用于对类进行版本控制(通过判断实体类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致InvalidCalssException的异常)

如何生成

Intellij IDEA可以自动为serializable的类生成一个serialVersionUID。

File->Preferences->Inspections->Serializationissues,将其展开后将serialzable class without "serialVersionUID"打上勾;
之后双击下class类名 ALT+ENTER即可生成随机的serialVersionUID
img_d54155d66a9d6112c5509cc558a976eb.png

img_4a2072c99d58f9a639e2acd48eb6e4fd.png
生成serialVersionUID

总结

  1. Java序列化就是把对象转换成字节序列,而Java反序列化就是把字节序列还原成Java对象,在java中可以通过实现Serializable和Externalizable两种接口实现序列化。
  2. 采用Java序列化与反序列化技术,一是可以实现数据的持久化,在MVC模式中很有用;二是可以对象数据的远程通信,序列化用于通信,服务端把数据序列化发送到客户端。客户端收到数据反序列化对数据操作。
  3. 序列化的好处:通过序列化可以把数据永久保存在硬盘上(通常放在文件里)
  4. transient关键字只能修饰属性,被transient修饰的属性将不会被序列化(这边的前提是实现Serializable接口,还有需注意被static修饰的属性也无法被序列化,static修饰的变量存在jvm内存中,如果反序列化后得到static修饰的属性,是从jvm取而不是反序列化后得到)。
  5. serialVersionUID主要用于反序列化的时候验证版本的一致性,常在jdk,各种jar包中使用。
目录
相关文章
|
20天前
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
38 1
|
2天前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第3天】在Java编程的世界里,对象序列化与反序列化是实现数据持久化和网络传输的关键技术。本文将深入探讨Java序列化的原理、应用场景以及如何通过代码示例实现对象的序列化与反序列化过程。从基础概念到实践操作,我们将一步步揭示这一技术的魅力所在。
|
2天前
|
分布式计算 资源调度 Hadoop
Hadoop-10-HDFS集群 Java实现MapReduce WordCount计算 Hadoop序列化 编写Mapper和Reducer和Driver 附带POM 详细代码 图文等内容
Hadoop-10-HDFS集群 Java实现MapReduce WordCount计算 Hadoop序列化 编写Mapper和Reducer和Driver 附带POM 详细代码 图文等内容
19 3
|
7天前
|
Java 数据库 对象存储
Java 序列化详解
本文详细解析了Java序列化的概念与应用。通过具体实例,深入探讨了其在对象存储和传输中的作用及实现方法,帮助读者理解如何有效利用这一特性来简化数据交换,并对其实现机制有了更深入的认识。
|
5天前
|
安全 网络协议 Java
Java反序列化漏洞与URLDNS利用链分析
Java反序列化漏洞与URLDNS利用链分析
23 3
|
7天前
|
Oracle Java 关系型数据库
|
15天前
|
存储 XML JSON
用示例说明序列化和反序列化
用示例说明序列化和反序列化
14 1
|
17天前
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
14天前
|
JSON 安全 编译器
扩展类实例的序列化和反序列化
扩展类实例的序列化和反序列化
28 0
|
2月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。