木蚂蚁手机乐园首页

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 6367|回复: 0

[开发入门] Java对象序列化(整理篇)

[复制链接]

该用户从未签到

51

主题

1

帖子

317

积分

木蚂蚁小学三年级

地穴编织者

Rank: 3

积分
317
发表于 2011-3-25 19:28:55 | 显示全部楼层 |阅读模式
本帖最后由 煮咖啡 于 2011-4-7 19:21 编辑

Java对象序列化(整理篇)

      在网上看了很多有关序列化的文章,我自己也写了两篇,现在感觉这些文 章都没有很好的把序列化说清楚(包括我自己在内),所以在此我将总结前人以及自己的经验,用更浅显易懂的语言来描述该机制,当然,仍然会有不好的地方,希 望你看后可以指出,作为一名程序员应该具有不断探索的精神和强烈的求知欲望!
序列化概述:
      简单来说序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化,流的概念这里不用多说(就是I/O),我们可以对流化后的对象进行 读写操作,也可将流化后的对象传输于网络之间(注:要想将对象传输于网络必须进行流化)!在对对象流进行读写操作时会引发一些问题,而序列化机制正是用来 解决这些问题的!
问题的引出:
      如上所述,读写对象会有什么问题呢?比如:我要将对象写入一个磁盘文件而后再将其读出来会有什么问题吗?别急,其中一个最大的问题就是对象引用!举个例子 来说:假如我有两个类,分别是A和B,B类中含有一个指向A类对象的引用,现在我们对两个类进行实例化{ A a = new A(); B b = new B(); },这时在内存中实际上分配了两个空间,一个存储对象a,一个存储对象b,接下来我们想将它们写入到磁盘的一个文件中去,就在写入文件时出现了问题!因为 对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,这样的话当我们从文件中恢复对象时(也就是重新加载到内存中)时,内存分配了三个 空间,而对象a同时在内存中存在两份,想一想后果吧,如果我想修改对象a的数据的话,那不是还要搜索它的每一份拷贝来达到对象数据的一致性,这不是我们所 希望的!
以下序列化机制的解决方案:
1.保存到磁盘的所有对象都获得一个序列号(1, 2, 3等等)
2. 当要保存一个对象时,先检查该对象是否被保存了。
3.如果以前保存过,只需写入"与已经保存的具有序列号x的对象相同"的标记,否则,保 存该对象
通过以上的步骤序列化机制解决了对象引用的问题!
序列化的实现:
      将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
例子:
  1. import java.io.*;
  2. public class Test
  3. {
  4.     public static void main(String[] args)
  5.     {
  6.         Employee harry = new Employee("Harry Hacker", 50000);
  7.         Manager manager1 = new Manager("Tony Tester", 80000);
  8.         manager1.setSecretary(harry);
  9.         
  10.         Employee[] staff = new Employee[2];
  11.         
  12.         staff[0] = harry;
  13.         staff[1] = manager1;
  14.         try
  15.         {
  16.             ObjectOutputStream out = new ObjectOutputStream(
  17.                 new FileOutputStream("employee.dat"));
  18.             out.writeObject(staff);
  19.             out.close();
  20.             
  21.             ObjectInputStream in = new ObjectInputStream(
  22.                 new FileInputStream("employee.dat"));
  23.             Employee[] newStaff = (Employee[])in.readObject();
  24.             in.close();
  25.    
  26.             /**
  27.              *通过harry对象来加薪
  28.              *将在secretary上反映出来
  29.              */
  30.             newStaff[0].raiseSalary(10);
  31.             
  32.             for (int i = 0; i < newStaff.length; i++)
  33.                 System.out.println(newStaff);
  34.         }
  35.         catch (Exception e)
  36.         {
  37.             e.printStackTrace();
  38.         }
  39.     }
  40.    
  41. }
  42. class Employee implements Serializable
  43. {
  44.     public Employee(String n, double s)
  45.     {
  46.         name = n;
  47.         salary = s;
  48.     }
  49.    
  50.     /**
  51.      *加薪水
  52.      */
  53.     public void raiseSalary(double byPercent)
  54.     {
  55.         double raise = salary * byPercent / 100;
  56.         salary += raise;
  57.     }
  58.    
  59.     public String toString()
  60.     {
  61.         return getClass().getName()
  62.             + "[name = "+ name
  63.             + ",salary = "+ salary
  64.             + "]";
  65.     }
  66.    
  67.     private String name;
  68.     private double salary;
  69. }
  70. class Manager extends Employee
  71. {
  72.     public Manager(String n, double s)
  73.     {
  74.         super(n, s);
  75.         secretary = null;
  76.     }
  77.    
  78.     /**
  79.      *设置秘书
  80.      */
  81.     public void setSecretary(Employee s)
  82.     {
  83.         secretary = s;
  84.     }
  85.    
  86.     public String toString()
  87.     {
  88.         return super.toString()
  89.             + "[secretary = "+ secretary
  90.             + "]";
  91.     }
  92.    
  93.     //secretary代表秘书
  94.     private Employee secretary;
  95. }
  96. 修改默认的序列 化机制:   
  97.       在序列化的过程中,有些数据字段我们不想将其序列化,对于此类字段我们只需要在定义时给它加上 transient关键字即可,对于transient字段序列化机制会跳过不会将其写入文件,当然也不可被恢复。但有时我们想将某一字段序列化,但它在 SDK中的定义却是不可序列化的类型,这样的话我们也必须把他标注为transient,可是不能写入又怎么恢复呢?好在序列化机制为包含这种特殊问题的 类提供了如下的方法定义:
  98. private void readObject(ObjectInputStream in) throws
  99.          IOException, ClassNotFoundException;
  100. private void writeObject(ObjectOutputStream out) throws
  101.          IOException;
复制代码

(注:这些方法定义时必须是私有的,因为不需要你显示调用,序列化机制会自动调用的)
使用以上方法我们可以手动对那些你又想序列 化又不可以被序列化的数据字段进行写出和读入操作。
      下面是一个典型的例子,java.awt.geom包中的 Point2D.Double类就是不可序列化的,因为该类没有实现Serializable接口,在我的例子中将把它当作LabeledPoint类中 的一个数据字段,并演示如何将其序列化!
  1. import java.io.*;
  2. import java.awt.geom.*;
  3. public class TransientTest
  4. {
  5.     public static void main(String[] args)
  6.     {
  7.         LabeledPoint label = new LabeledPoint("Book", 5.00, 5.00);
  8.         try
  9.         {
  10.             System.out.println(label);//写入前
  11.             ObjectOutputStream out = new ObjectOutputStream(new
  12.                 FileOutputStream("Label.txt"));
  13.             out.writeObject(label);
  14.             out.close();
  15.             
  16.             System.out.println(label);//写入后
  17.             
  18.             ObjectInputStream in = new ObjectInputStream(new
  19.                 FileInputStream("Label.txt"));
  20.             LabeledPoint label1 = (LabeledPoint)in.readObject();
  21.             in.close();
  22.             System.out.println(label1);//读出并加1.0后
  23.         }
  24.         catch (Exception e)
  25.         {
  26.             e.printStackTrace();
  27.         }
  28.     }
  29.    
  30. }
  31. class LabeledPoint implements Serializable
  32. {
  33.     public LabeledPoint(String str, double x, double y)
  34.     {
  35.         label = str;
  36.         point = new Point2D.Double(x, y);
  37.     }
  38.    
  39.     private void writeObject(ObjectOutputStream out) throws IOException
  40.     {
  41.         /**
  42.          *必须通过调用defaultWriteObject()方法来写入
  43.          *对象的描述以及那些可以被序列化的字段
  44.          */
  45.         out.defaultWriteObject();
  46.         out.writeDouble(point.getX());
  47.         out.writeDouble(point.getY());
  48.     }
  49.    
  50.     private void readObject(ObjectInputStream in)
  51.         throws IOException, ClassNotFoundException
  52.     {
  53.         /**
  54.          *必须调用defaultReadObject()方法
  55.          */
  56.         in.defaultReadObject();
  57.         double x = in.readDouble() + 1.0;
  58.         double y = in.readDouble() + 1.0;
  59.         point = new Point2D.Double(x, y);
  60.     }
  61.    
  62.     public String toString()
  63.     {
  64.         return getClass().getName()
  65.             + "[label = "+ label
  66.             + ", point.getX() = "+ point.getX()
  67.             + ", point.getY() = "+ point.getY()
  68.             + "]";
  69.     }
  70.    
  71.     private  String label;
  72.     transient private Point2D.Double point;
  73. }
复制代码


什么是java序列化,如何实现java序列化? 收藏
Java 串行化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从其它地方把该Byte 流里的数据读出来,重新构造一个相同的对象。这种机制允许你将对象通过网络进行传播, 并可以随时把对象持久化到数据库、文件等系统里。Java的串行化机制是RMI、EJB等技术的技术基础。用途:利用对象的串行化实现保存应用程序的当前工作状态,下次再启动的时候将自动地恢复到上次执行的状态。
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。 可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。
序列化的实现:将需要被序列化的类实现Serializable接口,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对 象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的 对象写出(即保存其状态), 要恢复的话则用输入流。
2、 串行化的特点:
    (1)如果某个类能够被串行化,其子类也可以被串行化。如果该类有父 类,则分两种情况来考虑,如果该父类已经实现了可串行化接口。则其父类的相应字段及属性的处理和该类相同;如果该类的父类没有实现可串行化接口,则该类的父类所有的字段属性将不 会串行化。
  (2)声明为static和transient类型的成员数据不能被串行化。因为static代表类的状态, transient代表对象的临时数据;
  (3)相关的类和接口:在java.io包中提供的涉及对象的串行化的类与接口有ObjectOutput接口、ObjectOutputStream类、ObjectInput接口、ObjectInputStream类。
    (1)ObjectOutput接口:它继承DataOutput接口并且支持对象的串行化,其内的writeObject()方法实现存储一个对象。ObjectInput接口:它继承DataInput接口并且支持对象的串行化,其内的readObject()方法实现读取一个对象。
    (2)ObjectOutputStream类:它继承OutputStream类并且实现ObjectOutput接口。利用该类来实现将对象存储(调用ObjectOutput接口中的writeObject()方法)。ObjectInputStream类:它继承InputStream类并且实现ObjectInput接口。利用该类来实现读取一个对象(调用ObjectInput接口中的readObject()方法)。
  对于父类的处理,如果父类没有实现串行化接口,则其必须有默认的构造函数(即没有参数的构造函数)。否则编译的时候就会报错。在反串行化的时候,默认构造函数会被调用。但是若把父类标记为可以串行化,则在反串行化的时候,其默认构造函数不会被调用。这是为什么呢?这是因为Java 对串行化的对象进行反串行化的时候,直接从流里获取其对象数据来生成一个对象实例,而不是通过其构造函数来完成。
  1. import java.io.*;
  2. public class Cat implements Serializable {
  3.         private String name;
  4.         public Cat () {
  5.                 this.name = "new cat";
  6.         }
  7.         public String getName() {
  8.                 return this.name;
  9.         }
  10.         public void setName(String name) {
  11.                 this.name = name;
  12.         }
  13.         public static void main(String[] args) {         
  14.                 Cat cat = new Cat();
  15.                 try {
  16.                         FileOutputStream fos = new FileOutputStream("catDemo.out");
  17.                         ObjectOutputStream oos = new ObjectOutputStream(fos);
  18.                         System.out.println(" 1> " + cat.getName());
  19.                         cat.setName("My Cat");                        
  20.                         oos.writeObject(cat);
  21.                         oos.close();                        
  22.                 } catch (Exception ex) {  ex.printStackTrace();   }
  23.                 try {
  24.                         FileInputStream fis = new FileInputStream("catDemo.out");
  25.                         ObjectInputStream ois = new ObjectInputStream(fis);
  26.                         cat = (Cat) ois.readObject();
  27.                         System.out.println(" 2> " + cat.getName());
  28.                         ois.close();
  29.                 } catch (Exception ex) {
  30.                         ex.printStackTrace();
  31.                 }
  32.         }
  33. }//writeObject和readObject本身就是线程安全的,传输过程中是不允许被并发访问的。所以对象能一个一个接连不断 的传过来
复制代码



该贴已经同步到 煮咖啡的微博
0.0 ……加油吧……
您需要登录后才可以回帖 登录 | 注册

本版积分规则

推荐版块: PC破解软件下载  |   VR视频资源下载  |   三星Galaxy S8/S8+  |   恋舞OL  |   安卓破解软件  |   安卓破解游戏     安卓汉化下载  
安卓android软件大全  |   安卓大型游戏  |   小米手机论坛  |   三星Galaxy Note8论坛  |   影视资源下载  |   安卓破解    
安卓市场   安卓软件   小说电子书大全   在线影音播放   PC破解游戏下载   安卓软件教程   安卓游戏攻略   手机游戏   手机健康软件   手机订餐软件   手机购物软件   热门TAG
快速回复 返回顶部 返回列表