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包中使用。
目录
相关文章
|
9天前
|
IDE Oracle Java
java基础教程(1)-Java概述和相关名词解释
【4月更文挑战第1天】Java是1995年Sun Microsystems发布的高级编程语言,以其跨平台特性著名。它介于编译型和解释型语言之间,通过JVM实现“一次编写,到处运行”。Java有SE、EE和ME三个版本,分别针对标准、企业及嵌入式应用。JVM是Java虚拟机,确保代码在不同平台无需重编译。JRE是运行环境,而JDK包含开发工具。要安装Java开发环境,可从Oracle官网下载JDK,设置JAVA_HOME环境变量并添加到PATH。
|
29天前
|
存储 C#
C#中的序列化和反序列化
C#中的序列化和反序列化
12 0
|
1月前
|
存储 Java 数据库
|
3天前
|
存储 Java
Java基础教程(7)-Java中的面向对象和类
【4月更文挑战第7天】Java是面向对象编程(OOP)语言,强调将事务抽象成对象。面向对象与面向过程的区别在于,前者通过对象间的交互解决问题,后者按步骤顺序执行。类是对象的模板,对象是类的实例。创建类使用`class`关键字,对象通过`new`运算符动态分配内存。方法包括构造函数和一般方法,构造函数用于对象初始化,一般方法处理逻辑。方法可以有0个或多个参数,可变参数用`类型...`定义。`this`关键字用于访问当前对象的属性。
|
4天前
|
Java 索引
Java基础教程(6)-Java中的流程控制语句
【4月更文挑战第6天】Java流程控制包括选择(if, switch)、重复(while, do-while, for)和跳转(break, continue, return)语句。选择语句根据条件执行不同路径,if和switch用于单条件和多条件分支。重复语句用于循环,如for循环的初始化、条件和迭代部分,以及while和do-while循环。跳转语句中,break用于立即退出循环,continue结束当前循环迭代,return则从方法中返回。此外,Java的for each循环简化了数组或集合的遍历,但不能控制遍历顺序或索引。
|
6天前
|
存储 Java
Java输入输出:解释一下序列化和反序列化。
Java中的序列化和反序列化是将对象转换为字节流和反之的过程。ObjectOutputStream用于序列化,ObjectInputStream则用于反序列化。示例展示了如何创建一个实现Serializable接口的Person类,并将其序列化到文件,然后从文件反序列化回Person对象。
15 5
|
6天前
|
存储 Java 编译器
Java基础教程(4)-Java中的操作符
【4月更文挑战第4天】Java中的String是常用类,字符串是不可变对象,用双引号表示。String对象在编译期长度受限于65535,运行期不超过Int范围。字符串方法如length()、substring()、replace()、equals()等提供了多种操作。可变字符串可使用StringBuffer或StringBuilder。String对象通过字符串池优化内存,池中已有相同内容字符串则返回其引用。
|
17天前
|
搜索推荐 Java
Java基础(快速排序算法)
Java基础(快速排序算法)
23 4
|
29天前
|
存储 C#
C#中的序列化和反序列化案例
C#中的序列化和反序列化案例
11 0
|
1月前
|
JSON Java Maven
使用Jackson进行 JSON 序列化和反序列化
使用Jackson进行 JSON 序列化和反序列化
23 0

热门文章

最新文章