广告
返回顶部
首页 > 资讯 > 精选 >关于Java序列化的问题有哪些
  • 201
分享到

关于Java序列化的问题有哪些

2023-06-02 11:06:31 201人浏览 安东尼
摘要

本篇内容主要讲解“关于Java序列化的问题有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“关于Java序列化的问题有哪些”吧!问题一:什么是 Java 序列化?序列化是把对象改成可以存到磁盘

本篇内容主要讲解“关于Java序列化的问题有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“关于Java序列化的问题有哪些”吧!

问题一:什么是 Java 序列化?

序列化是把对象改成可以存到磁盘或通过网络发送到其它运行中的 Java 虚拟机的二进制格式的过程,并可以通过反序列化恢复对象状态。Java 序列化api开发人员提供了一个标准机制:通过实现 java.io.Serializable 或者 java.io.Externalizable 接口,ObjectInputStream 及ObjectOutputStream 处理对象序列化。实现java.io.Externalizable 接口的话,Java 程序员可自由选择基于类结构的标准序列化或是它们自定义的二进制格式,通常认为后者才是最佳实践,因为序列化的二进制文件格式成为类输出 API的一部分,可能破坏 Java 中私有和包可见的属性的封装。

序列化到底有什么用?

实现 java.io.Serializable。

定义用户类:

class User implements Serializable {    private String username;    private String passwd;    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPasswd() {        return passwd;    }    public void setPasswd(String passwd) {        this.passwd = passwd;    }}

我们把对象序列化,通过ObjectOutputStream存储到txt文件中,再通过ObjectInputStream读取txt文件,反序列化成User对象。

public class TestSerialize {    public static void main(String[] args) {        User user = new User();        user.setUsername("hengheng");        user.setPasswd("123456");        System.out.println("read before Serializable: ");        System.out.println("username: " + user.getUsername());        System.err.println("passWord: " + user.getPasswd());        try {            ObjectOutputStream os = new ObjectOutputStream(                    new FileOutputStream("/Users/admin/Desktop/test/user.txt"));            os.writeObject(user); // 将User对象写进文件            os.flush();            os.close();        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        try {            ObjectInputStream is = new ObjectInputStream(new FileInputStream(                    "/Users/admin/Desktop/test/user.txt"));            user = (User) is.readObject(); // 从流中读取User的数据            is.close();            System.out.println("\nread after Serializable: ");            System.out.println("username: " + user.getUsername());            System.err.println("password: " + user.getPasswd());        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }}

运行结果如下:

序列化前数据: username: henghengpassword: 123456序列化后数据: username: henghengpassword: 123456

到这里,我们大概知道了什么是序列化。

问题二:序列化时,你希望某些成员不要序列化,该如何实现?

答案:声明该成员为静态或瞬态,在 Java 序列化过程中则不会被序列化。

  • 静态变量:加static关键字。

  • 瞬态变量: 加transient关键字。

我们先尝试把变量声明为瞬态。

class User implements Serializable {    private String username;    private transient String passwd;    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPasswd() {        return passwd;    }    public void setPasswd(String passwd) {        this.passwd = passwd;    }

在密码字段前加上了transient关键字再运行。运行结果:

序列化前数据: username: henghengpassword: 123456序列化后数据: username: henghengpassword: null

通过运行结果发现密码没有被序列化,达到了我们的目的。

再尝试在用户名前加static关键字。

class User implements Serializable {    private static String username;    private transient String passwd;    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPasswd() {        return passwd;    }    public void setPasswd(String passwd) {        this.passwd = passwd;    }

运行结果:

序列化前数据: username: henghengpassword: 123456序列化后数据: username: henghengpassword: null

我们发现运行后的结果和预期的不一样,按理说username也应该变为null才对。是什么原因呢?

原因是:反序列化后类中static型变量username的值为当前JVM中对应的静态变量的值,而不是反序列化得出的。

我们来证明一下:

public class TestSerialize {    public static void main(String[] args) {        User user = new User();        user.setUsername("hengheng");        user.setPasswd("123456");        System.out.println("序列化前数据: ");        System.out.println("username: " + user.getUsername());        System.err.println("password: " + user.getPasswd());        try {            ObjectOutputStream os = new ObjectOutputStream(                    new FileOutputStream("/Users/admin/Desktop/test/user.txt"));            os.writeObject(user); // 将User对象写进文件            os.flush();            os.close();        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        User.username = "小明";        try {            ObjectInputStream is = new ObjectInputStream(new FileInputStream(                    "/Users/admin/Desktop/test/user.txt"));            user = (User) is.readObject(); // 从流中读取User的数据            is.close();            System.out.println("\n序列化后数据: ");            System.out.println("username: " + user.getUsername());            System.err.println("password: " + user.getPasswd());        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }}class User implements Serializable {    public static String username;    private transient String passwd;    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPasswd() {        return passwd;    }    public void setPasswd(String passwd) {        this.passwd = passwd;    }}

在反序列化前把静态变量username的值改为『小明』。

User.username = "小明";

再运行一次:

序列化前数据: username: henghengpassword: 123456序列化后数据: username: 小明password: null

果然,这里的username是JVM中静态变量的值,并不是反序列化得到的值。

问题三:serialVersionUID有什么用?

我们经常会在类中自定义一个serialVersionUID:

private static final long serialVersionUID = 8294180014912103005L

这个serialVersionUID有什么用呢?如果不设置的话会有什么后果?

serialVersionUID 是一个 private static final long 型 ID,当它被印在对象上时,它通常是对象的哈希码。serialVersionUID可以自己定义,也可以自己去生成。

不指定 serialVersionUID的后果是:当你添加或修改类中的任何字段时,已序列化类将无法恢复,因为新类和旧序列化对象生成的 serialVersionUID 将有所不同。Java 序列化的过程是依赖于正确的序列化对象恢复状态的,并在序列化对象序列版本不匹配的情况下引发 java.io.InvalidClassException 无效类异常。

举个例子大家就明白了:

我们保持之前保存的序列化文件不变,然后修改User类。

class User implements Serializable {    public static String username;    private transient String passwd;    private String age;    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPasswd() {        return passwd;    }    public void setPasswd(String passwd) {        this.passwd = passwd;    }    public String getAge() {        return age;    }    public void setAge(String age) {        this.age = age;    }}

加了一个属性age,然后单另写一个反序列化的方法:

public static void main(String[] args) {        try {            ObjectInputStream is = new ObjectInputStream(new FileInputStream(                    "/Users/admin/Desktop/test/user.txt"));            User user = (User) is.readObject(); // 从流中读取User的数据            is.close();            System.out.println("\n修改User类之后的数据: ");            System.out.println("username: " + user.getUsername());            System.err.println("password: " + user.getPasswd());        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }

关于Java序列化的问题有哪些

报错了,我们发现之前的User类生成的serialVersionUID和修改后的serialVersionUID不一样(因为是通过对象的哈希码生成的),导致了InvalidClassException异常。

自定义serialVersionUID:

class User implements Serializable {    private static final long serialVersionUID = 4348344328769804325L;    public static String username;    private transient String passwd;    private String age;    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPasswd() {        return passwd;    }    public void setPasswd(String passwd) {        this.passwd = passwd;    }    public String getAge() {        return age;    }    public void setAge(String age) {        this.age = age;    }}

再试一下:

序列化前数据: username: henghengpassword: 123456序列化后数据: username: 小明password: null

运行结果无报错,所以一般都要自定义serialVersionUID。

问题四:是否可以自定义序列化过程?

答案当然是可以的。

之前我们介绍了序列化的第二种方式:

实现Externalizable接口,然后重写writeExternal() 和readExternal()方法,这样就可以自定义序列化。

比如我们尝试把变量设为瞬态。

public class ExternalizableTest implements Externalizable {    private transient String content = "我是被transient修饰的变量哦";    @Override    public void writeExternal(ObjectOutput out) throws IOException {        out.writeObject(content);    }    @Override    public void readExternal(ObjectInput in) throws IOException,            ClassNotFoundException {        content = (String) in.readObject();    }    public static void main(String[] args) throws Exception {        ExternalizableTest et = new ExternalizableTest();        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(                new File("test")));        out.writeObject(et);        ObjectInput in = new ObjectInputStream(new FileInputStream(new File(                "test")));        et = (ExternalizableTest) in.readObject();        System.out.println(et.content);        out.close();        in.close();    }}

运行结果:

我是被transient修饰的变量哦

这里实现的是Externalizable接口,则没有任何东西可以自动序列化,需要在writeExternal方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关。

到此,相信大家对“关于Java序列化的问题有哪些”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: 关于Java序列化的问题有哪些

本文链接: https://www.lsjlt.com/news/229879.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 关于Java序列化的问题有哪些
    本篇内容主要讲解“关于Java序列化的问题有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“关于Java序列化的问题有哪些”吧!问题一:什么是 Java 序列化?序列化是把对象改成可以存到磁盘...
    99+
    2023-06-02
  • 关于Dubbo的问题有哪些
    这篇文章主要讲解了“关于Dubbo的问题有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“关于Dubbo的问题有哪些”吧!1、RPC1.1 RPC 定义互...
    99+
    2022-10-19
  • 关于Spring的问题有哪些
    这篇文章主要讲解了“关于Spring的问题有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“关于Spring的问题有哪些”吧!1 Spring核心组件一句...
    99+
    2022-10-19
  • 关于jackson序列化和feign返回值的问题
    目录jackson序列化和feign返回值jackson注意点feignClient 返回值问题feign调用异常,反序列化失败异常消息如下jackson序列化和feign返回值 j...
    99+
    2022-11-13
  • Java中关于消息队列的面试题有哪些
    这篇文章将为大家详细讲解有关Java中关于消息队列的面试题有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。面试题1:说说你对消息队列的理解,消息队列为了解决什么问题?我们公司业务系统一开始体量较小,很...
    99+
    2023-06-20
  • Java序列化与hessian序列化的区别有哪些
    Java序列化与hessian序列化的区别有哪些?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。     &nb...
    99+
    2023-05-31
    java hessian ava
  • Java程序员比较关心的问题有哪些
    本篇内容介绍了“Java程序员比较关心的问题有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Question1:我是双非/三本/专科学校...
    99+
    2023-06-19
  • 关于Java IO的面试题有哪些
    本篇内容介绍了“关于Java IO的面试题有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!  1.IO里面的常见类,字节流、字符流、接口...
    99+
    2023-06-02
  • java序列化的方式有哪些
    Java序列化的方式有:1. 实现Serializable接口:在需要序列化的类中实现Serializable接口,该接口没有任何方...
    99+
    2023-09-27
    java
  • java序列化方式有哪些
    Java序列化方式有以下几种:1. Java默认的序列化:通过实现Serializable接口来实现,默认使用ObjectOutpu...
    99+
    2023-08-15
    java
  • 有关Java反射的问题有哪些
    这篇文章主要讲解了“有关Java反射的问题有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“有关Java反射的问题有哪些”吧!反射可以修改final类型成员变量吗final我们应该都知道,...
    99+
    2023-06-15
  • 关于Ubuntu 18.04的常见问题有哪些
    关于Ubuntu 18.04的常见问题有哪些,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Ubuntu 18.04 版本 已经到来。我可以在各种 Faceboo...
    99+
    2023-06-16
  • 关于Python的面试问答题有哪些
    这篇文章主要介绍“关于Python的面试问答题有哪些”,在日常操作中,相信很多人在关于Python的面试问答题有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”关于Python的面试问答题有哪些”的疑惑有所...
    99+
    2023-06-16
  • 关于Python迭代器的问题有哪些
    这篇文章主要讲解了“关于Python迭代器的问题有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“关于Python迭代器的问题有哪些”吧!第一个问题:什么是迭代器迭代器,英文  ...
    99+
    2023-06-16
  • 有哪些Java GC的相关问题
    这篇文章主要介绍“有哪些Java GC的相关问题”,在日常操作中,相信很多人在有哪些Java GC的相关问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”有哪些Java GC的相关问题”的疑惑有所帮助!接下来...
    99+
    2023-06-16
  • Redis分布式锁遇到的序列化问题有哪些
    这篇文章主要介绍Redis分布式锁遇到的序列化问题有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!问题排查既然是释放锁有问题,那就先看看释放锁的代码吧。释放锁释放锁使用了 Lua 脚本,代码逻辑和 Lua 脚本如...
    99+
    2023-06-14
  • Java中关于锁的面试题有哪些
    这篇文章主要介绍Java中关于锁的面试题有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Java有哪些集合类Java中的集合主要分为四类:1、List列表:有序的,可重复的;2、Queue队列:有序,可重复的;3...
    99+
    2023-06-14
  • 有哪些关于Java集合的面试题
    本篇内容主要讲解“有哪些关于Java集合的面试题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“有哪些关于Java集合的面试题”吧!HashMap和HashTable有何不同?  (1)HashM...
    99+
    2023-06-02
  • java类序列化的原因有哪些
    Java类序列化的原因有以下几个:1. 数据持久化:将对象转化为字节流的形式,可以将其保存到磁盘文件或者通过网络传输,以实现数据的持...
    99+
    2023-08-24
    java
  • Python关于面向对象的问题有哪些
    这篇“Python关于面向对象的问题有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python关于面向对象的问题有哪些...
    99+
    2023-07-06
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作