浅析关于java的序列化和反序列化

 更新时间:2023年07月26日 11:53:52   作者:yasooooo  
这篇文章主要介绍了浅析关于java的序列化和反序列化,所谓序列化,就是把要传输的对象以及相关信息转换成字节数组进行存储的过程,而反序列化就是将字节数组再转回对象的过程,需要的朋友可以参考下

对于序列化和反序列化,大家或多或少都会听过一点。

所谓序列化,就是把要传输的对象以及相关信息转换成字节数组进行存储的过程。

而反序列化就是将字节数组再转回对象的过程。

对于序列化和反序列化总结了几点需要注意的地方,

1、实现Serializable接口的类才能够序列化,如果是父类实现了该接口,子类也可以进行序列化

这点不过多解释,规定就是这样。

2、静态成员不能被序列化、方法不能被序列化,关键字transient修饰的属性不能序列化

话不多说,上代码。

import java.io.*;
/**
 * 测试静态成员、方法、transient修饰的属性不能序列化
 */
public class SerializeTest {
    public static void main(String[] args) throws IOException {
        Test test = new Test(); // 创建被序列化的对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.data"));
        oos.writeObject(test);
        oos.close(); //这里记得序列化完成之后要关流,和io流一样,不多解释
    }
}
class Test implements Serializable{ //创建一个类用于创建序列化对象
    static int a;
    transient private int b;
    private int c;
    public void m(){}
}

以上代码就是创建了一个类,然后对该类的对象进行序列化,序列化后的文件为test.data.然后查看了一个这个文件的大小为53字节。

下面我将这个类中的静态成员、transient修饰的成员和m()方法都注释掉再进行一次序列化

import java.io.*;
/**
 * 测试静态成员、方法、transient修饰的属性不能序列化
 */
public class SerializeTest {
    public static void main(String[] args) throws IOException {
        Test test = new Test(); // 创建被序列化的对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.data"));
        oos.writeObject(test);
        oos.close(); //这里记得序列化完成之后要关流,和io流一样,不多解释
    }
}
class Test implements Serializable{ // 将static属性、transient属性和方法都注释掉之后在进行一次序列化
//    static int a;
//    transient private int b;
    private int c;
//    public void m(){}
}

此时,看到再序列化之后的文件大小依然还是53字节,但是如果再将成员变量c注释掉再进行序列化就会发现,这个文件变小了

由此可以说明,静态成员、transient修饰的成员和方法都不能序列化。

3、对于向上造型的对象进行序列化,实际序列化的对象是实际创建类

上代码

 
import java.io.*;
/**
 * 测试向上造型的对象实际序列化的是实际创建类
 */
public class SerializeTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Test test = new Test02();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test02.data"));
        oos.writeObject(test);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test02.data"));
        System.out.println(ois.readObject()); //这里直接打印反序列化之后的对象信息
        ois.close();
    }
}
class Test implements Serializable{ //创建一个父类类用于创建序列化对象
}
class Test02 extends Test{    // 子类继承父类
}

上面代码的执行结果:Test02@4f3f5b24,可以看到打印的就是子类的对象,so,这个就证明了向上造型的对象,实际序列化的是实际创建类,同时也证明了如果父类实现了Serializable接口,子类也是可以序列化滴。

4、对于已经序列化完的对象,在进行反序列化时,如果对原类信息进行了修改(包含不能被序列化的属性和方法),此时将不能进行反序列化

直接上代码。

 
import java.io.*;
/**
 * 测试反序列化之前如果修改原类信息将不能进行反序列化
 * 
 */
public class SerializeTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test02.data"));
        System.out.println(ois.readObject()); //这里直接打印反序列化之后的对象信息
        ois.close();
    }
}
class Test implements Serializable{ //创建一个父类类用于创建序列化对象
}
class Test02 extends Test{    // 子类继承父类
    // test02.data这个文件就是第三条中创建对象序列化之后的文件
    static int a = 1;    //这里我随便添加了一个静态属性,然后执行代码
}

///下面是执行结果
Exception in thread "main" java.io.InvalidClassException: night.Test02; local class incompatible: stream classdesc serialVersionUID = -4461189770521473347, local class serialVersionUID = -7303293535763263875
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1829)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1986)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
    at night.SerializeTest.main(SerializeTest.java:23)

居然报了异常?

这里为什么会报异常呢,简单讲一哈:序列化的时候会计算一个序列化版本号-----serialVersionUID,并且将这个版本号一同存放到文件中,在反序列化的时候会获取此序列号,并且会计算当前类的serialVersionUID,如果两个版本号不相等就会报如上异常,反之反序列化就可以成功。~

那么对于这种情况就没有解决办法了? 当然是有的。

我们可以在类中直接声明serialVersionUID为 final属性,并让其自动赋初始值(这个值jvm肯定是计算过的了),格式如下:

private static final long serialVersionUID = 362498820763181265L;

这样不管怎样修改类的属性,这个serialVersionUID都不会改变,这样问题就解决了。

其实对于private static final long serialVersionUID = 362498820763181265L;这个东西,大家应该都见过的,比如我这里拿的就是HashMap类源码中的那个值。

以上就是浅析关于java的序列化和反序列化的详细内容,更多关于java序列化和反序列化的资料请关注脚本之家其它相关文章!

相关文章

  • java组件commons-fileupload实现文件上传、下载、在线打开

    java组件commons-fileupload实现文件上传、下载、在线打开

    这篇文章主要介绍了java组件commons-fileupload实现文件上传、下载、在线打开,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • Spring底层核心源码原理解析

    Spring底层核心源码原理解析

    这篇文章主要介绍了Spring底层核心源码原理解析,当在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事务,而这个方法所在的类所对应的Bean对象会是该类的代理对象,需要的朋友可以参考下
    2023-09-09
  • java文件上传下载功能实现代码

    java文件上传下载功能实现代码

    这篇文章主要为大家详细介绍了java文件上传下载功能实现代码,具有一定的参考价值,感兴趣的朋友可以参考一下
    2016-06-06
  • 基于Java实现文件和base64字符串转换

    基于Java实现文件和base64字符串转换

    这篇文章主要介绍了基于Java实现文件和base64字符串转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • springmvc+mybatis 做分页sql 语句实例代码

    springmvc+mybatis 做分页sql 语句实例代码

    本文通过一段实例代码给大家介绍了springmvc+mybatis 做分页sql 语句的方法,代码简单易懂,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-07-07
  • idea配置springboot热部署终极解决办法(解决热部署失效问题)

    idea配置springboot热部署终极解决办法(解决热部署失效问题)

    这篇文章主要介绍了idea配置springboot热部署终极解决办法(解决热部署失效问题),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-07-07
  • Java Class 加密工具 ClassFinal详解

    Java Class 加密工具 ClassFinal详解

    ClassFinal 是一款 java class 文件安全加密工具,支持直接加密jar包或war包,无需修改任何项目代码,兼容spring-framework;可避免源码泄漏或字节码被反编译,这篇文章主要介绍了Java Class 加密工具 ClassFinal,需要的朋友可以参考下
    2023-03-03
  • SpringMVC实现账号只能在一处登陆

    SpringMVC实现账号只能在一处登陆

    这篇文章主要为大家详细介绍了SpringMVC如何实现账号只能在一处登陆,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • SpringBoot JPA使用配置过程详解

    SpringBoot JPA使用配置过程详解

    这篇文章主要介绍了SpringBoot JPA使用配置过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • javaSE中异常如何处理举例详解

    javaSE中异常如何处理举例详解

    程序运行过程中发生了不正常的情况,这种不正常的情况叫做异常,下面这篇文章主要给大家介绍了关于javaSE中异常如何处理的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-01-01

最新评论