【Java学习笔记】对象的序列化和反序列化

简介: 作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 1.定义: 序列化,也叫串行化--将对象写到一个输出流(一般是一个文件)中。反序列化则是从一个输入流中读取一个对象。

作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/

1.定义:

序列化,也叫串行化--将对象写到一个输出流(一般是一个文件)中。反序列化则是从一个输入流中读取一个对象。类中的成员必须是可序列化的,而且要实现Serializable接口,这样的类的对象才能被序列化和反序列化。这个接口是一个表示型的接口。serialVersionUID 是一个串行化类的通用标示符,反串行化就是使用这个标示符确保一个加载的类对应一个可串行化的对象。

若自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法可以用。serialVersionUID的生成,可以写1,也可以写2,但最好还是按照摘要算法,生成一个惟一的指纹数字,eclipse可以自动生成的,jdk也自带了这个工具。一般写法类似于
private static final long serialVersionUID = -763618247875550322L;

 

简单的使用请参加我的另一篇习作:http://blog.csdn.net/gnuhpc/archive/2009/08/01/4396149.aspx

 

2.序列化步骤:

1)创建一个对象输出流:可以包装一个其他类型的输出流。

2)通过对象输出流的writeObject()写对象。注意使用类型转化,转换为相应的类的对象。

3.反序列化步骤:

1)创建一个对象输入流:可以包装一个其他类型的输出流。

2)通过对象输出流的readObject()写对象。

4.什么对象需要被序列化?

序列化的基本想法是完成对实例信息的保证。因为实例信息在运行结束后就消失了。要储存什么信息呢?一定不是关于方法的信息。

 

5.使用注意事项:

a.有些属性处于安全考虑不能被序列化(或者不能被序列化,比如Thread),则用transit修饰,若想进一步控制序列化和反序列化,则类中提供readObject()方法和writeObject()方法,(反)序列化时就会调用自定义的方法。注意这两个方法不是在java.io.Serializable接口定义的,而是在ObjectInputStream和ObjectOutputStream类中定义的,这两个类实现ObjectInput 和ObjectOutput两个接口。下边是一个可变数组的例子,取自Java in a Nutshell 2rd Edition,它在串行化实现了高效的针对可变数组程度调整的方法:

 

b.由于串行化是针对类的实例,也就是对象的,所以static这样的成员是类相关的,也就不会被串行化。
c.注意,API中一个类一旦被串行化了,那么它的父类都是串行化的。你自己设计的类要是想被串行化,那么其父类要确保都串行化。父类一旦串行化,则子类们都自动实现了串行化。所以内部类和可扩展类不建议串行化。

d. 若想加密序列化的数据,可以重写writeObject和readObject,并将加密算法写入其中,最后调用stream.defaultWriteObject();或者stream.defaultReadObject();实现模糊化——当然,你若是想在序列化和反序列化前后执行任何操作都可以在这里定制,比如,这个类的父类实现了串行化,但你并不希望这个类可以被串行化,那么就可以在串行化和反串行化的时候抛出异常:

 

 

 

如果需要对整个对象进行加密和签名,最简单的是将它放在一个 javax.crypto.SealedObject 和/或 java.security.SignedObject 包装器中。两者都是可序列化的,所以将对象包装在 SealedObject 中可以围绕原对象创建一种 “包装盒”。必须有对称密钥才能解密,而且密钥必须单独管理。同样,也可以将 SignedObject 用于数据验证,并且对称密钥也必须单独管理。

e.序列化不是针对的对象的文件和方法,而是对象的状态,因此在反序列化时对象的类文件必须存在。

f.若想创建自己的串行化方式请实现Externalizable接口,而不是Serializable接口,重写下边两个方法:

 

public void writeExternal(ObjectOutput out) throws IOException;

public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

注意这里你没有了默认的动作可以做,一切都要靠自己。除此之外这个接口与串行化接口没有区别。默认的串行化方法可能会带来时间开销,若你想优化的话,不妨从自定义简单串行化方法开始。这个接口的实际用途在于若你想串行化父类的数据成员,那么依靠原始的串行化接口是无法满足的,你必须自定义串行化方法:

[java:nogutter] view plain copy
  1. import java.io.*; 
  2. public class TestExternalizable 
  3. FileOutputStream fout = null
  4. ObjectOutputStream objOut = null
  5.  public TestExternalizable() { 
  6.  try
  7.    TestSub testSub = new TestSub(); 
  8.    testSub.setName(NAME); 
  9.    testSub.setAge(AGE); 
  10.    fout = new FileOutputStream(FILE_NAME); 
  11.    objOut = new ObjectOutputStream(fout); 
  12.    objOut.writeObject(testSub); 
  13.    objOut.flush(); 
  14.    objOut.close(); 
  15.    fout.close(); 
  16.    FileInputStream fin = new FileInputStream(FILE_NAME); 
  17.    ObjectInputStream objIn = new ObjectInputStream(fin); 
  18.    TestSub ts = (TestSub)objIn.readObject(); 
  19.    objIn.close(); 
  20.    fin.close(); 
  21.    System.out.println(ts.name+" "+ts.age); 
  22. } catch(Exception ex) { 
  23.      ex.printStackTrace(); 
  24.  public static void main(String[] args) 
  25.    new TestExternalizable(); 
  26. class TestSuper{ 
  27. String name = null
  28.  int age = 0
  29.  public void setName(String name) { 
  30.  this.name = name; 
  31.  public void setAge(int age) { 
  32.    this.age = age; 
  33.  public void readExternal(ObjectInput objectInput) { 
  34.    try
  35.      name = (String)objectInput.readObject(); 
  36.      age = objectInput.readInt(); 
  37.    } catch(Exception ex) { 
  38.      ex.printStackTrace(); 
  39.    } 
  40.  public void writeExternal(ObjectOutput objectOutput) { 
  41.    try 
  42.    { 
  43.      objectOutput.writeObject(name); 
  44.      objectOutput.writeInt(age); 
  45.    } catch (Exception ex) { 
  46.      ex.printStackTrace(); 
  47.    } 
  48. class TestSub extends TestSuper implements Externalizable { 
  49.    public TestSub() { 
  50.    } 
import java.io.*; public class TestExternalizable { FileOutputStream fout = null; ObjectOutputStream objOut = null; public TestExternalizable() { try{ TestSub testSub = new TestSub(); testSub.setName(NAME); testSub.setAge(AGE); fout = new FileOutputStream(FILE_NAME); objOut = new ObjectOutputStream(fout); objOut.writeObject(testSub); objOut.flush(); objOut.close(); fout.close(); FileInputStream fin = new FileInputStream(FILE_NAME); ObjectInputStream objIn = new ObjectInputStream(fin); TestSub ts = (TestSub)objIn.readObject(); objIn.close(); fin.close(); System.out.println(ts.name+" "+ts.age); } catch(Exception ex) { ex.printStackTrace(); } } public static void main(String[] args) { new TestExternalizable(); } } class TestSuper{ String name = null; int age = 0; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void readExternal(ObjectInput objectInput) { try{ name = (String)objectInput.readObject(); age = objectInput.readInt(); } catch(Exception ex) { ex.printStackTrace(); } } public void writeExternal(ObjectOutput objectOutput) { try { objectOutput.writeObject(name); objectOutput.writeInt(age); } catch (Exception ex) { ex.printStackTrace(); } } } class TestSub extends TestSuper implements Externalizable { public TestSub() { } }  

h.你若是在一个打开的流中写了两次,第二次是不会被保存的,若想重新写要调用ObjectOutputStream.reset() 方法。

 

作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/


               作者:gnuhpc
               出处:http://www.cnblogs.com/gnuhpc/
               除非另有声明,本网站采用知识共享“署名 2.5 中国大陆”许可协议授权。


分享到:

目录
相关文章
|
1月前
|
安全 Java 编译器
Java对象一定分配在堆上吗?
本文探讨了Java对象的内存分配问题,重点介绍了JVM的逃逸分析技术及其优化策略。逃逸分析能判断对象是否会在作用域外被访问,从而决定对象是否需要分配到堆上。文章详细讲解了栈上分配、标量替换和同步消除三种优化策略,并通过示例代码说明了这些技术的应用场景。
Java对象一定分配在堆上吗?
|
1月前
|
存储 安全 Java
🌟Java零基础-反序列化:从入门到精通
【10月更文挑战第21天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
72 5
|
1月前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
29 3
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
1月前
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
33 0
|
4月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
4月前
|
存储 开发框架 .NET
解锁SqlSugar新境界:利用Serialize.Linq实现Lambda表达式灵活序列化与反序列化,赋能动态数据查询新高度!
【8月更文挑战第3天】随着软件开发复杂度提升,数据查询的灵活性变得至关重要。SqlSugar作为一款轻量级、高性能的.NET ORM框架,简化了数据库操作。但在需要跨服务共享查询逻辑时,直接传递Lambda表达式不可行。这时,Serialize.Linq库大显身手,能将Linq表达式序列化为字符串,实现在不同服务间传输查询逻辑。结合使用SqlSugar和Serialize.Linq,不仅能够保持代码清晰,还能实现复杂的动态查询逻辑,极大地增强了应用程序的灵活性和可扩展性。
151 2
|
1月前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
2月前
|
存储 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。
|
2月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第3天】在Java编程的世界里,对象序列化与反序列化是实现数据持久化和网络传输的关键技术。本文将深入探讨Java序列化的原理、应用场景以及如何通过代码示例实现对象的序列化与反序列化过程。从基础概念到实践操作,我们将一步步揭示这一技术的魅力所在。