`
ywChen
  • 浏览: 120107 次
  • 性别: 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++ JSON 序列化与反序列化

    本篇文章将深入探讨C++中JSON的序列化与反序列化。 **一、JSON序列化** 序列化是指将C++的对象转换为JSON字符串的过程,以便在网络上传输或保存到文件中。常见的C++ JSON序列化库有RapidJSON、nlohmann/json、...

    C#对象序列化反序列化保存与读取和对象直接保存与读取

    2. **对象序列化与反序列化**: 序列化是将对象转换为可存储或传输的形式,如字节流或文本,而反序列化则是将这些形式恢复为原始对象。C#中的`System.Runtime.Serialization`命名空间提供了多种序列化工具,如`...

    XML序列化与反序列化 实战

    XML序列化与反序列化是.NET框架中处理数据交换的重要技术,它允许我们将对象的状态转换为XML格式的数据,也可以将XML数据恢复为等效的对象。这个实战项目专注于使用C#实现这一过程,使得开发者能够方便地在XML文件和...

    C#序列化与反序列化(包括复杂xml对象)

    本文将深入探讨C#中的XML序列化和反序列化技术,包括如何将XML文档解析为对象,以及如何将对象转换回XML文档进行存储。我们将详细讲解三种方法,涵盖从XML节点获取键值对(KV值)到处理对象数组和节点标签组合的反...

    序列化和反序列化的封装类

    反序列化时,我们需要确保接收的数据与原始对象类型匹配,否则可能会抛出异常。 为了简化序列化和反序列化的操作,开发者通常会创建一个封装类,该类提供简单的API供其他代码调用。例如,我们可以创建一个名为`...

    hessian学习基础篇——序列化和反序列化

    在IT领域,序列化和反序列化是两个关键的概念,特别是在网络通信、数据持久化以及对象存储中。本文将深入探讨Hessian框架的基础知识,它是一个高效的二进制序列化协议,广泛应用于Java和.NET之间跨语言通信。通过...

    用Javascript将form所有内容序列化和反序列化的例子。

    本文将深入探讨如何使用JavaScript对表单数据进行序列化和反序列化。 序列化是将数据结构或对象转换为字符串的过程,便于存储或传输。在HTML表单中,序列化通常是指将表单元素的值转换为URL编码的字符串,以便通过...

    Java对象的序列化和反序列化实践

    总结,Java对象的序列化和反序列化是Java开发中不可或缺的一部分,理解并熟练掌握这些技术可以帮助我们更好地处理数据存储和传输的问题。在实际操作时,应根据具体需求选择合适的方法,并注意相关的安全和性能问题。

    Java中的序列化与反序列化.pdf

    上述工具类提供了序列化的方法`mySerialize()`,它接受一个对象和一个文件名作为参数,将对象序列化并保存到指定的文件中。 反序列化则是将字节流转换回原来的对象,这个过程可以通过`ObjectInputStream`类的`...

    delphi序列化与反序列化

    本文将深入探讨Delphi中的序列化与反序列化,以及如何处理组件和结构体的序列化。 首先,让我们了解什么是序列化。序列化是指将一个对象的状态转换为可以存储或传输的数据格式的过程。这通常是一个二进制流或者XML...

    序列化和反序列化dll文件和proto

    总的来说,理解和掌握序列化和反序列化技术对于任何IT专业人员来说都是至关重要的,无论是在处理DLL文件以实现模块化开发,还是在使用Proto进行高效的数据交换。正确使用这些技术能够提高代码的可维护性、减少网络...

    C#对象三种形式的序列化和反序列化

    在C#编程中,序列化和反序列化是将对象的状态转换为可存储或传输的形式,然后恢复为原始...在给定的示例中,`Serialization0819`这个压缩包文件可能包含了演示这些序列化方法的代码示例,可以帮助深入理解这些概念。

    序列化与反序列化Demo

    序列化与反序列化是计算机科学中的重要概念,特别是在数据存储、网络通信和持久化对象等领域。简单来说,序列化是将对象的状态转换为可存储或传输的数据格式的过程,而反序列化则是将这种数据格式恢复为原来的对象...

    C#和Java的序列化反序列化

    本篇文章将深入探讨C#和Java中的序列化与反序列化机制。 首先,我们要了解什么是序列化。序列化是指将对象的状态转化为可存储或可传输的数据格式的过程。这个过程通常将内存中的对象转换成字节流,以便保存到磁盘、...

    Java中对象序列化与反序列化详解

    本文将深入探讨Java中的对象序列化与反序列化的概念、原理、实现方法以及相关的注意事项。 **一、对象序列化的概念和作用** 对象序列化是将一个Java对象转换成字节流的过程,这个字节流可以存储在磁盘上,也可以在...

    C#序列化和反序列化案例.rar

    在这个“C#序列化和反序列化案例”中,我们可以通过提供的代码示例深入理解这两个概念。 首先,序列化是将对象的状态转换为可以存储或传输的数据格式的过程。在C#中,我们可以使用内置的System.Runtime....

    Java对象序列化标准最新版

    ### Java对象序列化标准知识点详解 #### 一、系统架构概览 **1.1 概览** Java 对象序列化是一种将Java对象的状态转换成字节流的过程,以便于在网络上传输或存储到磁盘上。Java序列化标准定义了一套规则来描述如何...

    Jedis序列化和反序列化使用jar

    本文将深入探讨在使用Jedis时如何处理对象的序列化和反序列化,以及相关依赖库的作用。 首先,让我们了解什么是序列化和反序列化。序列化是将对象的状态转换为可存储或传输的形式的过程,而反序列化则是将这种形式...

    C#序列化与反序列化

    本文将深入探讨C#中的序列化与反序列化机制,以及相关的知识点。 一、什么是C#序列化 C#序列化是指将一个对象的实例转换为一组字节流,这通常用于保存对象的状态以便稍后恢复,或者在网络之间传输对象。C#提供了...

Global site tag (gtag.js) - Google Analytics