`
ywChen
  • 浏览: 117912 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

对象的序列化与反序列化深入理解

    博客分类:
  • J2SE
阅读更多

序列化工具类

 

package serializable;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * 对象序列化
 * @author chenyw
 *
 */
public class ObjectSerialize {

	//序列化对象存储路径
	private static final String objectFilePath ="d:\\objectFile.obj";
	
	/**
	 * 序列化对象
	 * @param obj
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public void objectOutput(Object obj) throws FileNotFoundException, IOException{
		FileOutputStream fileos = new FileOutputStream(objectFilePath);
		ObjectOutputStream out = new ObjectOutputStream(fileos);
		//序列化对象
		out.writeObject(obj);
		out.close();
	}
	
	/**
	 * 反序列化
	 * @return Object
	 * @throws FileNotFoundException
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public Object objectInput() throws FileNotFoundException, IOException, ClassNotFoundException{
		FileInputStream fileis = new FileInputStream(objectFilePath);
		//反序列化
		ObjectInputStream in = new ObjectInputStream(fileis);
		Object obj = in.readObject();
		in.close();
		return obj;
	}
	/**
	 * @param args
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 */
	public static void main(String[] args) throws Exception {
		ObjectSerialize  os = new ObjectSerialize();
		//..... ....待序列化及反序列化代码
	}

}

 

 

1.序列化注意事项

 

   ObjectOuputStream只能对实现了Serializable接口的类的对象进行序列化,默认情况下,ObjectOuputStream 按照默认方式序列化,这种序列化方式仅仅对对象的非treasient的实例变量进行那个序列化,而不会序列化对象的transient的实例变量,也不会序列化静态变量。

 

 

package serializable;

import java.io.Serializable;

/**
 * 要序列化的对象Customer1
 * 
 * @author chenyw
 *  
 */
public class Customer1 implements Serializable {
  private static int count; //用于计算Customer对象的数目,不被序列化
  private static final int MAX_COUNT=1000;
  private String name;
  private transient String password;//不被序列化
  
  static{
     System.out.println("调用Customer1类的静态代码块");
  }
  public Customer1(){
    System.out.println("调用Customer1类的不带参数的构造方法");
    count++;
  }
  public Customer1(String name, String password) {
    System.out.println("调用Customer1类的带参数的构造方法");
    this.name=name;
    this.password=password;
    count++;
  }
  public String toString() {
    return "count="+count
           +" MAX_COUNT="+MAX_COUNT
           +" name="+name
           +" password="+ password;
  }
}

 

先在ObjectSerialize mian函数下添加,执行对象序列化

 

ObjectSerialize  os = new ObjectSerialize();
Customer1 c = new Customer1("yuwen","123456");
System.out.println("待序列化对象:"+c);
os.objectOutput(c);

 控制台输出:

 

调用Customer1类的静态代码块

调用Customer1类的带参数的构造方法

待序列化对象:count=1 MAX_COUNT=1000 name=yuwen password=123456

 

ObjectSerialize mian函数下添加,执行对象反序列化

 

ObjectSerialize  os = new ObjectSerialize();
System.out.println("序列化后----");
System.out.println("反序列化后对象:"+os.objectInput());

 控制台输出:

 

序列化后----

调用Customer1类的静态代码块

反序列化后对象:count=0 MAX_COUNT=1000 name=yuwen password=null

 

以上可以通过输出可看到

     (1)transient 关键子的password不被序列化;

     (2)static count不被序列化,当加载Customer类时,count初始化为0。

 

在执行序列化及反序列化不能同时加载同一个类,不然最后反序列化的时候静态变量已经初始化了。

不同时执行序列化及反序列化这样能保证你序列化的类在反序列化之前没有加载,因为静态变量在类加载的时候已经赋值了,所有当处于同一jvm中时,你创建的任何一个对象都拥有这个静态变量。

 

 

2.序列化对象图

 

   类与类之间可能存在关联关系。如下所示的Customer2类与Order2类之间存在一对多的双向关联关系。

 

package serializable;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/**
 * 客户对象类
 * @author chenyw
 *
 */
public class Customer2 implements Serializable{

	private String name;
	private Set<Order2> orders = new HashSet<Order2>();
	static{
		System.out.println("调用Customer2类的静态代码块");
	}
	public Customer2(){
		System.out.println("调用Customer2类的不带参数的构造方法");
	}
	public Customer2(String name){
		System.out.println("调用Customer2类的带参数的构造方法");
		this.name=name;
	}
	
	public void addOrder(Order2 order){
		orders.add(order);
	}
	
	public String toString(){
		String result = super.toString()+","+orders+"\r\n";
		return result;
	}
}
 

 

package serializable;

import java.io.Serializable;
/**
 * 订单对象类
 * @author chenyw
 *
 */
public class Order2 implements Serializable{

	private String number;
	private Customer2 customer;
	public Order2(){
		System.out.println("调用Order2类的不带参数的构造方法");
	}
	public Order2(String number,Customer2 customer){
		System.out.println("调用Order2类的带参数的构造方法");
		this.number = number;
		this.customer = customer;
	}
}
 

  在ObjectSerialize mian函数添加以下代码,建立他们的关联关系:

 

//客户chenyw有两个订单,订单编号分别为“number1”和“number2”
Customer2 customer = new Customer2("chenyw");
Order2 order1 = new Order2("number1",customer );
Order2 order2 = new Order2("number2",customer );
customer.addOrder(order1);
customer.addOrder(order2);

 进行序列化及反序列化

反序列化后输出如下

    反序列化后对象:serializable.Customer2@60aeb0,[serializable.Order2@89ae9e,      serializable.Order2@1270b73]

 

在默认方式下,对象输出流会对整个对象图进行序列化。当程序执行writeObject(customer)方法时,该方法不仅序列化Customer2对象,还会把两个与它关联的Order2对象也进行序列化。

 

如下图所示,简单的说,在内存中可以从对象A导航到对象B,序列化对象A时,实际上会序列化对象A,以及所有可以从对象A直接或间接导航到的对象。

按照默认方式序列化对象A时,实际上被序列化的对象图中包括:对象A、对象B、对象C、对象D、对象E、对象F和对象G。

3.控制序列化的行为

 

当序列化传输的过程中如用户的密码是保密的不公开的,就得对密码进行加密或不序列化

对象实现以下方法即可自定义序列化

 

 private void writeObject(ObjectOutputStream obj)throws IOException{
        obj.defaultWriteObject();
        //然后做自己的扩展序列化
     }
    
     private void readObject(ObjectInputStream obj) throws IOException,ClassNotFoundException{
       obj.defaultReadObject();
       //然后做自己的拓展反序列化
         
     }

 

【例】在序列化用户时将密码按位取反

 

import java.io.*;
public class Customer3 implements Serializable {
  private static int count; //用于计算Customer3对象的数目
  private static final int MAX_COUNT=1000;
  private String name;
  private transient String password;
  
  static{
     System.out.println("调用Customer3类的静态代码块");
  }
  public Customer3(){
    System.out.println("调用Customer3类的不带参数的构造方法");
    count++;
  }
  public Customer3(String name, String password) {
    System.out.println("调用Customer3类的带参数的构造方法");
    this.name=name;
    this.password=password;
    count++;
  }

  /** 加密数组,将buff数组中的每个字节的每一位取反 
   *  例如13的二进制为00001101,取反后为11110010
   */
  private byte[] change(byte[] buff){
    for(int i=0;i<buff.length;i++){
      int b=0;
      for(int j=0;j<8;j++){
        int bit=(buff[i]>>j & 1)==0 ? 1:0;
        b+=(1<<j)*bit;
      }
      buff[i]=(byte)b;
    }
    return buff;
  }

  private void writeObject(ObjectOutputStream stream)throws IOException {
    stream.defaultWriteObject();  //先按默认方式序列化 
    stream.writeObject(change(password.getBytes()));
    stream.writeInt(count);
  }

  private void readObject(ObjectInputStream stream)
          throws IOException, ClassNotFoundException {
    stream.defaultReadObject();  //先按默认方式反序列化
    byte[] buff=(byte[])stream.readObject();
    password = new String(change(buff));
    count=stream.readInt();
  }

  public String toString() {
    return "count="+count
           +" MAX_COUNT="+MAX_COUNT
           +" name="+name
           +" password="+ password;
  }
}
 

 

 

 

 

 

 

 

 

  • 大小: 13.8 KB
分享到:
评论

相关推荐

    深入理解C#序列化与反序列化的详解

    在我们深入探讨C#序列化和反序列化之前我们先要明白什么是序列化,它又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的...

    深入理解Java对象的序列化与反序列化的应用

    本篇文章是对Java中对象的序列化与反序列化进行了详细的分析介绍,需要的朋友参考下

    深入理解:XML与对象的序列化与反序列化

    这篇文章主要讲述XML与对象的序列化与反序列化。并且会附上一些简单的序列化与反序列化方法,供大家使用。假设我们在一个Web项目中有这样两个类复制代码 代码如下:public class Member { public string Num { get; ...

    c#-对象的txt保存、序列化和反序列化

    实现对象的保存、读取文本文件、二进制序列化和反序列化。通过这些实例,我们能够深入了解如何将对象的属性信息以不同的方式进行持久化,并在需要时再次还原,从而提高数据的可管理性和可维护性。

    深入理解Java原生的序列化机制

    Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。下面小编和大家来一起学习一下吧

    深入理解C#中的XML,完整扫描版

    《深入理解C#中的XML》主要讲述C#软件开发中的XML的功能,全书共10章,分别介绍了XML基础语法、应用文档对象模型、用XSLT转换XML文档、利用DTD和XSDSchema验证XML文档、XML文档的读取、ADO.NET的相关知识、....

    panko_serializer:ActiveRecord和Ruby对象的高性能JSON序列化

    潘科 Panko是一个受ActiveModelSerializers 0.9启发的库,用于将ActiveRecord / Ruby对象快速序列化为JSON字符串。... 要深入了解性能选择,请阅读《 。 支持 加入我们的 执照 根据的规定,该gem可作为开源软件。

    Python面向对象编程指南

    第2部分讲述持久化和序列化,分别介绍了序列化和保存、用Shelve保存和获取对象、用SQLite保存和获取对象、传输和共享对象、配置文件和持久化;第3部分讲述测试、调试、部署和维护,分别介绍了Logging和Warning模块、...

    深入 .NET平台和C#编程

    序列化与反射 8. Video 教学 Video: 演示 新闻阅读器 功能 9. 附录 类库中主要命名空间 数据结构 10. 指导学习 DLC 1 DLC 2 DLC 3 11. 在线培训 无 12. 项目案例 影院售票 13. 阶段...

    Java实例高难度面试题及解析 - 展现你的编程实力!

    此外,我们还探讨了对象的哈希码、重写equals()和hashCode()方法的技巧,以及对象的序列化和反序列化。 通过研究和解答这些高难度问题,您将提升自己的编程水平,展现出对Java实例概念和相关技术的深入理解。无论您...

    【Java面试+Java学习指南】 一份涵盖大部分Java程序员所需要掌握的核心知识

    序列化和反序列化 继承、封装、多态的实现原理 容器 Java集合类总结 Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解2:Queue和LinkedList Java集合详解3:Iterator,fail-fast机制...

    Java工程师面试复习指南

    序列化和反序列化 继承封装多态的实现原理 集合类 Java集合类总结 Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解:Queue和LinkedList Java集合详解:迭代器,快速失败机制与比较器...

    net之美 : .net关键技术深入解析 (带目录高清版)

    第二部分(6~17 章)则对.NET 中的关键知识点进行了深入剖 析,如程序集、流和序列化、加密与解密、网络编程、.NET Remoting、在.NET 中操作XML、.NET 应 用程序配置、基于角色的安全性、反射、多线程、对象生存期与...

    深入解析MFC

    更深入地了解MFC序列化中那些没有文档记录的方面和一些没有文档记录的类,例如CPreview、CPreviewDC、CMirrorFile以及CDockBar等等;最后理解MFC 和OLE是如何共同运作的,以及OLE控悠扬是如何实现的;积累技巧,学会...

    .NET之美:.NET关键技术深入解析 - 张子阳

    第二部分(6~17章)则对.NET中的关键知识点进行了深入剖析,如程序集、流和序列化、加密与解密、网络编程、.NET Remoting、在.NET中操作XML、.NET应用程序配置、基于角色的安全性、反射、多线程、对象生存期与垃圾...

    .NET之美:.NET关键技术深入解析

    第二部分(6~17 章)则对.NET 中的关键知识点进行了深入剖 析,如程序集、流和序列化、加密与解密、网络编程、.NET Remoting、在.NET 中操作XML、.NET 应 用程序配置、基于角色的安全性、反射、多线程、对象生存期与...

    网络多人游戏架构与编程

    从网络游戏的基本概念、互联网、伯克利套接字、对象序列化、对象复制、网络拓扑和游戏案例、延迟、抖动和可靠性、改进的延迟处理、可扩展性、安全性、真实世界的引擎、玩家服务、云托管专用服务器等方面深入介绍了...

    深入Python3 中文版

    《深入 Python 3》中有何新内容 安装 Python ...Python 对象序列化 HTTP Web 服务 案例研究:将 chardet 移植到 Python 3 Python 类库打包 使用 2to3 将代码移植到 Python 3 特殊方法名称 接下来阅读什么?

    JAVA基础课程讲义

    JAVA对象的序列化和反序列化 161 为什么需要序列化和反序列化 161 对象的序列化主要有两种用途 161 序列化涉及的类和接口 162 序列化/反序列化的步骤和实例 162 综合的序列化和反序列化练习 163 JAVA.IO包相关流对象...

Global site tag (gtag.js) - Google Analytics