【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 中国大陆”许可协议授权。


分享到:

目录
相关文章
|
8月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
1022 157
|
8月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
409 1
|
8月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
384 1
|
10月前
|
缓存 安全 Java
Java反射机制:动态操作类与对象
Java反射机制是运行时动态操作类与对象的强大工具,支持获取类信息、动态创建实例、调用方法、访问字段等。它在框架开发、依赖注入、动态代理等方面有广泛应用,但也存在性能开销和安全风险。本文详解反射核心API、实战案例及性能优化策略,助你掌握Java动态编程精髓。
|
10月前
|
存储 人工智能 JavaScript
Java从作用域到对象高级应用​
本内容详细讲解了JavaScript中的作用域类型(函数作用域、块作用域、全局作用域)、作用域链、垃圾回收机制、闭包、变量提升、函数参数、数组方法、内置构造函数、对象高级知识、原型链、对象赋值、深浅拷贝、递归、异常处理及this指向等内容,全面覆盖JS核心概念与编程技巧。
126 0
【Java】— —实现人物对象的增、删、改、查(注:对象的删除以逻辑删除为主,在person类中设置“删除状态字段”,字删除该字段时,将状态改为有效。)
【Java】— —实现人物对象的增、删、改、查(注:对象的删除以逻辑删除为主,在person类中设置“删除状态字段”,字删除该字段时,将状态改为有效。)
|
存储 Java
Java的对象和类的相同之处和不同之处
在 Java 中,对象和类是面向对象编程的核心。
285 19
|
存储 Java
Java编程中的对象和类
【8月更文挑战第55天】在Java的世界中,“对象”与“类”是构建一切的基础。就像乐高积木一样,类定义了形状和结构,而对象则是根据这些设计拼装出来的具体作品。本篇文章将通过一个简单的例子,展示如何从零开始创建一个类,并利用它来制作我们的第一个Java对象。准备好让你的编程之旅起飞了吗?让我们一起来探索这个神奇的过程!
164 10
|
Java
Java 对象和类
在Java中,**类**(Class)和**对象**(Object)是面向对象编程的基础。类是创建对象的模板,定义了属性和方法;对象是类的实例,通过`new`关键字创建,具有类定义的属性和行为。例如,`Animal`类定义了`name`和`age`属性及`eat()`、`sleep()`方法;通过`new Animal()`创建的`myAnimal`对象即可调用这些方法。面向对象编程通过类和对象模拟现实世界的实体及其关系,实现问题的结构化解决。
189 4
|
机器学习/深度学习 人工智能 算法
探索人工智能在医疗诊断中的应用与挑战Java编程中的对象和类:基础与实践
【8月更文挑战第27天】随着人工智能(AI)技术的飞速发展,其在医疗领域的应用日益广泛。本文深入探讨了AI技术在医疗诊断中的具体应用案例,包括图像识别、疾病预测和药物研发等方面,并分析了当前面临的主要挑战,如数据隐私、算法偏见和法规限制等。文章旨在为读者提供一个全面的视角,理解AI在改善医疗服务质量方面的潜力及其局限性。