Java基础巩固-关于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(); } } }
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
总结
- Java序列化就是把对象转换成字节序列,而Java反序列化就是把字节序列还原成Java对象,在java中可以通过实现Serializable和Externalizable两种接口实现序列化。
- 采用Java序列化与反序列化技术,一是可以实现数据的持久化,在MVC模式中很有用;二是可以对象数据的远程通信,序列化用于通信,服务端把数据序列化发送到客户端。客户端收到数据反序列化对数据操作。
- 序列化的好处:通过序列化可以把数据永久保存在硬盘上(通常放在文件里)
- transient关键字只能修饰属性,被transient修饰的属性将不会被序列化(这边的前提是实现Serializable接口,还有需注意被static修饰的属性也无法被序列化,static修饰的变量存在jvm内存中,如果反序列化后得到static修饰的属性,是从jvm取而不是反序列化后得到)。
- serialVersionUID主要用于反序列化的时候验证版本的一致性,常在jdk,各种jar包中使用。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
吐槽net下没有靠谱的FastDFS的sdk之使用thrift实现JAVA和C#互通
原文: 吐槽net下没有靠谱的FastDFS的sdk之使用thrift实现JAVA和C#互通 事情是这样的,在一个新项目中引入了fastdfs,用这玩意做一些小数据的存储还是很方便的,然后在nuget上就找到了一个FastDFS的sdk,如下图: 一眼就看到了这个top1的sdk,应该会比较靠谱。。。简单的在项目中应用了一下没啥问题就忽悠上线了,然后就悲剧了,测试那边反馈说上传了一个 人群,拉下来的时候少了几个人,我的使用方式是将一批customerid按照bitmap的形式存到byte[]数组传到fastdfs,最后硬着头皮追踪下来发现是这个所谓 的sdk在upload的时候在bytes数组处理上出了bug,这下无语了,哎,nuget上这写sdk的估计也就是个人写着玩玩丢上去的,哪里敢用到生产上,还好在测 试环境发现了,不然又得出什么乱子了。 一:解决办法 问题还得要解决,不过庆幸的是,fastdfs是阿里的一个大牛YuQing写的,那应该有java的sdk更靠谱一点,用maven的话更方便。 <dependency> <groupId>...
- 下一篇
CentOS 7.5 + PHP 5.6.36 + Nginx 1.14.0 配置笔记
本文首发 http://zhaoda.net/2018/05/22/centos-php-nginx/转载请注明出处 创建用户、组和目录 # web 用户和组 groupadd www useradd -g www www -s /sbin/nologin # 网站目录 mkdir -p /data/htdocs # 日志目录 mkdir -p /data/logs # 创建软件包下载和编译目录,后续软件都下载到这里 mkdir -p /data/software # 创建软件安装目录,PHP、Nginx 将安装到这里 mkdir -p /usr/local/webserver # 可写目录进行如下设置 # chown -R www:www /path 服务器基础环境和依赖安装 # 如果系统自带 Apache、PHP、MySQL,先卸载 yum remove httpd yum remove php yum remove mysql # 升级所有软件包 yum update -y # 安装可能用到的软件包,大部分其实已经内置在系统中 # gcc:GNU 编译器套装 # gcc-c++:...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果