- 浏览: 2184463 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (682)
- 软件思想 (7)
- Lucene(修真篇) (17)
- Lucene(仙界篇) (20)
- Lucene(神界篇) (11)
- Solr (48)
- Hadoop (77)
- Spark (38)
- Hbase (26)
- Hive (19)
- Pig (25)
- ELK (64)
- Zookeeper (12)
- JAVA (119)
- Linux (59)
- 多线程 (8)
- Nutch (5)
- JAVA EE (21)
- Oracle (7)
- Python (32)
- Xml (5)
- Gson (1)
- Cygwin (1)
- JavaScript (4)
- MySQL (9)
- Lucene/Solr(转) (5)
- 缓存 (2)
- Github/Git (1)
- 开源爬虫 (1)
- Hadoop运维 (7)
- shell命令 (9)
- 生活感悟 (42)
- shell编程 (23)
- Scala (11)
- MongoDB (3)
- docker (2)
- Nodejs (3)
- Neo4j (5)
- storm (3)
- opencv (1)
最新评论
-
qindongliang1922:
粟谷_sugu 写道不太理解“分词字段存储docvalue是没 ...
浅谈Lucene中的DocValues -
粟谷_sugu:
不太理解“分词字段存储docvalue是没有意义的”,这句话, ...
浅谈Lucene中的DocValues -
yin_bp:
高性能elasticsearch ORM开发库使用文档http ...
为什么说Elasticsearch搜索是近实时的? -
hackWang:
请问博主,有用solr做电商的搜索项目?
Solr中Group和Facet的用法 -
章司nana:
遇到的问题同楼上 为什么会返回null
Lucene4.3开发之第八步之渡劫初期(八)
(一)什么是序列化和反序列化
序列化(serialization)和反序列化(deserialization)是将对象转化成字节数组以方便保存或者用于网络传输,这个对象可以是一个图片,一个字符串,一个class等等,常见序列化格式有字节数组,json格式,xml格式,更加高效的有google开源的Protocol Buffers,以及Apache Avro。
(二)为什么需要序列化和反序列化
(1)实现数据持久化,一般jvm的里面数据,在java程序退出时,所有的状态都不会保留,通过序列化可以将需要的数据给持久化到磁盘文件或者数据库,这样就可以在下次jvm启动的时候再把数据重新还原出来。
(2)利用序列化实现远程通信,即在网络上传送对象的字节序列,这种场景一般在socket或者rpc的服务中比较常见。
(三)Java里面如何实现序列化和反序列化
在java里面有两种方式可以实现对象的序列化:
(1)实现Serializable接口的类,jdk会自动帮我们序列化该类所有的信息,
但如果用户定义了writeObject和readObject方法,那么在序列化和反序列化的时候会通过反射优先调用自定义的方法
(2)实现Externalizable接口的类,需要用户自定义序列化和反序列化的逻辑,分别重写writeExternal和readExternal方法。
下面看一个例子,首先我们定义一个Person类并实现了:
````java public class Person implements Serializable { private static final long serialVersionUID = 1L;//序列化版本 private static String code="001";//code码 private transient String address;//地址 private String name;//姓名 private int age;//年龄 //getter setter 省略 //构造方法省略 //toString 方法省略 } ````
然后我们定义了帮助实现序列化和反序列化的工具类:
```` public class SerializeTools { /*** * 将任何实现了序列化接口的对象转成字节数组 * @param obj * @return * @throws Exception */ public static byte[] toBytes(Serializable obj) throws Exception{ ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(obj); return byteArrayOutputStream.toByteArray(); } /**** * 将任何序列化的字节数组,给还原成对象 * @param bytes * @return * @throws Exception */ public static Object toObj(byte[] bytes) throws Exception{ ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(bytes); ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream); Object obj=objectInputStream.readObject(); return obj; } /*** * 将一个实现了序列化的对象,给序列化成文件 * @param obj * @param storePath * @throws Exception */ public static void toFile(Serializable obj,String storePath)throws Exception{ FileOutputStream fileOutputStream=new FileOutputStream(new File(storePath)); ObjectOutputStream objectOutputStream=new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(obj); } /*** * 将序列化文件还原成对象 * @param storePath * @return * @throws Exception */ public static Object fromFile(String storePath)throws Exception{ FileInputStream fileInputStream=new FileInputStream(new File(storePath)); ObjectInputStream objectInputStream=new ObjectInputStream(fileInputStream); Object obj=objectInputStream.readObject(); return obj; } } ````
然后看下我们的测试类,分别测试文件的序列化和字节的序列化
```` public static void main(String[] args) throws Exception { Person p1=new Person("北京海淀","张三",25); fileTest(p1);//文件测试序列化和反序列化 System.out.println("=========================="); byteTest(p1);//字节测试序列化和反序列化 } public static void fileTest(Person p1) throws Exception{ String storePath="E://temp.out"; System.out.println("基于文件序列化前:"+p1); SerializeTools.toFile(p1,storePath); Person p2=(Person) SerializeTools.fromFile(storePath); System.out.println("基于文件反序列化后:"+p2); } public static void byteTest(Person p1) throws Exception{ System.out.println("基于字节序列化前:"+p1); byte[] bytes= SerializeTools.toBytes(p1);//序列化成字节数组 Person p2=(Person) SerializeTools.toObj(bytes);//反序列化成对象 System.out.println("基于字节反序列化后:"+p2); } ````
运行后输出如下:
```` 基于文件序列化前:Person{name='张三', age=25, code=001, address=北京海淀} 基于文件反序列化后:Person{name='张三', age=25, code=001, address=null} ========================== 基于字节序列化前:Person{name='张三', age=25, code=001, address=北京海淀} 基于字节反序列化后:Person{name='张三', age=25, code=001, address=null} ````
细心的同学可能已经发现地址这个字段,在反序列化后字段值丢失了,这里说明下:
(1)在java里面transient关键词修饰的成员变量是不会被序列化的,这一点在上面的输出中已经得到验证了,注意transient关键词只能修饰成员变量,不能修饰类和方法
(2)在java里面static关键词修饰的字段也是不会被序列化的,因为这个是类的字段,而序列化是针对对象的。
引申一下:java的内存分配有栈和堆以及永久代,栈中存放基本变量,数组和对象引用,堆中存放对象,当有static修饰的变量或方法会被放到永久代里面。它先于对象而存在,不依赖实例,无论是变量,方法,还是代码块,只要用static修饰,就是在类被加载时就已经准备好了,也就是可以被使用或者已经被执行,都可以脱离对象而执行,所以在类加载时静态变量的值其实已经还原出来了之后才是反序列化出来成员变量的值。
(3)在上面的Person类里面,相信大家还看到了一个用static final long修饰的 serialVersionUID字段,这个字段的功能是用来标识类版本的兼容性:
举个例子,假如现在没有定义serialVersionUID这个字段,jdk默认是根据类信息计算一个版本值,在类已经被序列化成文件后,我们又修改了类结构,比如新增了几个字段,这个时候拿着新版本的类去反序列化旧版本的类,就会抛出下面的异常:
```` ocal class incompatible: stream classdesc serialVersionUID = 3980523453097177768, local class serialVersionUID = -2111153241298098896 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373) at com.xuele.tools.tool.SerializeTools.fromFile(SerializeTools.java:57) ````意思就是版本不一致,导致失败,如果我们定义这个值,并且新旧版本的值一样,不管新增没新增字段,都可以反序列化成功,默认新增字段的值是jdk给成员变量初始化的值,比如字符串就是null。
(四)定制自己的序列化和反序列化方法
上面提到过实现了Serializable接口的类,我们可以重写下面的方法来自定义序列化逻辑:
```` private void writeObject(ObjectOutputStream out) throws Exception { System.out.println("call write"); // out.defaultWriteObject(); out.writeObject(name); out.writeInt(age); out.writeObject(address); } private void readObject(ObjectInputStream in) throws Exception { System.out.println("call read"); // in.defaultReadObject(); name = (String) in.readObject(); age=in.readInt(); address = (String) in.readObject(); } ````
再次执行测试方法:
```` 基于文件序列化前:Person{name='张三', age=25, code=001, address=北京海淀} call write call read 基于文件反序列化后:Person{name='张三', age=25, code=001, address=北京海淀} ========================== 基于字节序列化前:Person{name='张三', age=25, code=001, address=北京海淀} call write call read 基于字节反序列化后:Person{name='张三', age=25, code=001, address=北京海淀} ````
这次我们发现了被transient修饰的address字段竟然也有值了,为什么?因为我们自定义序列化的时候把地址也给序列化了,所以这个时候无论你用不用transient关键词都无关紧要了。
注意如果实现了上面的方法其实和使用Externalizable就相差无几了,所以在这里不再给出Externalizable的例子
(五)什么时候应该readObject和writeObject
在effective java里面提到过:
当一个对象的物理表示方法与它的逻辑数据内容有实质性差别时,使用默认序列化形式有N种缺陷。
其实是建议我们重写的,这样可以更好的控制序列化的过程,如果能减少一些不必要的序列化的字段,其实对我们的程序性能也是一种提升。
总结:
本文介绍了Java里面序列化和反序列化功能和使用以及一些注意事项,序列化其实还提供了深度克隆的功能,尤其是当类里面的引用层次比较多及引用特别复杂的时候,通过序列化来深度拷贝对象也是一种比较便利的方法,除此之外,我们还应该知道序列化和反序列化和反射一样,弱化了java安全权限修饰符的作用,无论你privte还是protected修饰的字段,在序列化和反射面前都是无作用的,所以一些敏感信息的序列化尤其是在网络上传输的如密码,金钱什么的,都应该考虑加密或者其他安全措施。
发表评论
-
记一次log4j不打印日志的踩坑记
2019-09-22 01:58 1567### 起因 前几天一个跑有java应用的生产集群(200多 ... -
在Java里面如何解决进退两难的jar包冲突问题?
2019-07-23 19:10 1232如上图所示: es api组件依赖guava18.0 ... -
如何轻松理解二叉树的深度遍历策略
2019-07-03 23:33 1127我们知道普通的线性数据结构如链表,数组等,遍历方式单一 ... -
为什么单线程Redis性能也很出色
2019-01-21 18:02 2207高性能的服务器,不一 ... -
如何将编程语言里面的字符串转成数字?
2019-01-11 23:23 2092将字符串转成数字在很 ... -
为什么Java里面String类是不可变的
2019-01-06 18:36 1667在Java里面String类型是不可变对象,这一点毫无疑问,那 ... -
关于Java里面volatile关键字的重排序
2019-01-04 18:49 1067Java里面volatile关键字主 ... -
多个线程如何轮流打印ABC特定的次数?
2018-12-11 20:42 6041之前的一篇文章,我给 ... -
聊聊Java里面的引用传递
2018-11-16 21:21 989长久以来,在Java语言里面一直有一个争论,就是Java语言到 ... -
理解计数排序算法的原理和实现
2018-10-11 10:03 2091计数排序(Counting sort) ... -
理解Java7和8里面HashMap+ConcurrentHashMap的扩容策略
2018-09-06 11:31 3389### 前言 理解HashMap和Con ... -
关于Java里面多线程同步的一些知识
2018-07-18 09:45 1107# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
Java单例模式之双检锁深入思考
2018-07-08 12:25 3289# Java单例模式之双检锁 ... -
关于Java里面多线程同步的一些知识
2018-07-08 12:23 1121# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
重新认识同步与异步,阻塞和非阻塞的概念
2018-07-06 14:30 1473# 重新认识同步与异步 ... -
线程的基本知识总结
2018-06-27 16:27 1061### (一)创建线程的方式 (1)实现Runnable接口 ... -
Java里面volatile关键字修饰引用变量的陷阱
2018-06-25 11:42 1386# Java里面volatile关键字修饰引用变量的陷阱 如 ... -
关于Java里面的字符串拼接,你了解多少?
2018-06-25 11:28 1370# 关于Java里面的字符串 ... -
深入理解Java内存模型的语义
2018-06-25 11:39 739### 前言 Java内存模型( ... -
如何证明Java多线程中的成员变量数据是互不可见的
2018-06-21 10:09 1501前面的几篇文章主要介绍了Java的内存模型,进程和线程的定义, ...
相关推荐
Java反序列化是一种将已序列化的对象状态转换回对象的过程,它是Java平台中持久化数据的一种常见方式。在Java应用程序中,序列化用于保存对象的状态以便稍后恢复,或者在网络间传输对象。然而,这个过程也可能引入...
Java对象的序列化和反序列化是Java编程中一项重要的技术,主要用于将对象的状态转换为字节流,以便存储或在网络上传输。这一过程对于理解Java的IO操作、持久化数据以及实现分布式通信等场景非常关键。 首先,我们来...
而在Java中,我们可以通过实现`Serializable`接口来使类支持序列化,或者使用`java.io.ObjectOutputStream`和`java.io.ObjectInputStream`进行对象的序列化和反序列化。 接下来,我们讨论反序列化。反序列化是序列...
**一、Java序列化** 1. **什么是序列化**:序列化是将对象的状态(属性和成员变量)转换为可以存储或传输的数据格式的过程。在Java中,通常是将对象转换为字节数组,以便写入磁盘或通过网络发送。 2. **为什么需要...
Java中的JSON(JavaScript Object Notation)序列化与反序列化是开发过程中常见且重要的操作,主要用于数据交换和存储。JSON是一种轻量级的数据交换格式,它允许我们将Java对象转换为JSON字符串,反之亦然,方便在...
1. **Java序列化机制**:Java对象序列化是通过实现`Serializable`接口来标记一个类可被序列化。`ObjectOutputStream`用于将对象写入流,`ObjectInputStream`用于从流中读取并反序列化对象。 2. **易受攻击的库**:...
### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化的概念 序列化是指将程序中的对象转换为一系列字节流的过程,主要用于保存对象的状态或在网络之间传输对象。序列化的主要目的是为了能够持久化...
在Java编程语言中,序列化和反序列化是两种重要的技术,它们允许我们将对象的状态转换为字节流,以便存储到磁盘上或通过网络进行传输。这些技术在处理持久化数据、对象缓存以及跨进程通信(如RMI - 远程方法调用)时...
标题"Java反序列化工具.zip"暗示了这个压缩包包含了一些工具,这些工具可能是为了帮助开发者理解、测试或者防御Java反序列化漏洞而设计的。可能包括模拟攻击的payload生成器,或者用于检测和修复此类漏洞的分析工具...
总的来说,理解和掌握序列化和反序列化技术对于任何IT专业人员来说都是至关重要的,无论是在处理DLL文件以实现模块化开发,还是在使用Proto进行高效的数据交换。正确使用这些技术能够提高代码的可维护性、减少网络...
在IT领域,序列化和反序列化是两个关键的概念,特别是在网络通信、数据持久化以及对象存储中。本文将深入探讨Hessian框架的基础知识,它是一个高效的二进制序列化协议,广泛应用于Java和.NET之间跨语言通信。通过...
在Java编程语言中,对象的序列化和反序列化是两个关键的概念,它们允许我们将对象的状态转换为可存储或传输的格式,然后再恢复为原始对象。这个过程对于数据持久化、网络传输以及跨进程通信等场景非常有用。下面将...
管理系统源码.zip、README.txt 在本项目中,“学生管理系统(序列化和反序列化)”是一个基于Java或类似编程语言实现的系统,其核心功能是...在开发类似的系统时,理解并掌握序列化和反序列化的核心原理是非常重要的。
Java对象的序列化和反序列化是Java编程中的一项重要技术,主要应用于数据持久化、网络传输等场景。本课件详细介绍了这一概念及其在实际应用中的操作。 首先,序列化是将Java对象转化为字节序列的过程,目的是为了...
Java序列化是Java平台提供的一种持久化机制,它允许我们将Java对象转换成字节流,以便于存储或者在网络中传输。这一过程被称为序列化,而将字节流还原成原来的对象则称为反序列化。在Java中,实现序列化主要通过实现...
`Newtonsoft.Json.dll`是.NET框架下的Json.NET库,它提供了JSON序列化和反序列化的功能,但在这个场景下可能与Java反序列化无关,除非系统中混合使用了.NET和Java技术。`Run.exe`是一个Windows可执行文件,可能用于...
在Java编程中,对象的序列化与反序列化是实现数据持久化和网络传输的关键技术。序列化是将对象的状态转换为字节流的过程,以便可以将其保存到文件、...希望本文能帮助你更好地理解和应用Java中的序列化与反序列化技术。
### Java对象序列化标准知识点详解 #### 一、系统架构概览 **1.1 概览** Java 对象序列化是一种将Java对象的...以上内容涵盖了Java序列化标准的关键知识点,深入了解这些概念有助于更好地理解和应用Java序列化技术。
Java序列化机制的优点在于它提供了一种标准的方式来处理对象的持久化和在网络间的传输。然而,序列化也存在安全风险,比如序列化可能导致远程代码执行攻击。因此,对于敏感信息或复杂对象结构,应谨慎使用序列化,并...
3. **数据格式**:Java序列化生成的字节流是平台和版本相关的,不适用于跨平台或跨语言通信。 4. **替代方案**:Java序列化并不是唯一的选择。例如,JSON、XML、protobuf等轻量级序列化库提供了更高效、更安全的...