`
kobe学java
  • 浏览: 257944 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

对于Java序列化的一次认识 转javaeye(感觉不错)

    博客分类:
  • java
 
阅读更多

其实这个问题简单思考一下就可以搞清楚,方法是不带状态的,就是一些指令,指令是不需要序列化的,只要你的JVM classloader可以load到这个类,那么类方法指令自然就可以获得。序列化真正需要保存的只是对象属性的值,和对象的类型。 

这些知识找一本Java基础编程的书,或者Java手册就可以查到,我以为是不应该犯这种基本概念错误的。 

我们可以做一个简单的小试验,来证实一下: 

Java代码 复制代码
  1. package com.javaeye;   
  2.   
  3. import java.io.Serializable;   
  4.   
  5. public class DomainObject  implements Serializable {   
  6.   
  7.     private String name;   
  8.        
  9.     private int age ;   
  10.   
  11.     public int getAge(); {   
  12.         return age;   
  13.      }   
  14.   
  15.     public void setAge(int age); {   
  16.         this.age = age;   
  17.      }   
  18.   
  19.     public String getName(); {   
  20.         return name;   
  21.      }   
  22.   
  23.     public void setName(String name); {   
  24.         this.name = name;   
  25.      }   
  26.        
  27.        
  28. }  
Java代码   收藏代码
  1. package com.javaeye;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class DomainObject  implements Serializable {  
  6.   
  7.  private String name;  
  8.    
  9.  private int age ;  
  10.   
  11.  public int getAge(); {  
  12.   return age;  
  13.  }  
  14.   
  15.  public void setAge(int age); {  
  16.   this.age = age;  
  17.  }  
  18.   
  19.  public String getName(); {  
  20.   return name;  
  21.  }  
  22.   
  23.  public void setName(String name); {  
  24.   this.name = name;  
  25.  }  
  26.    
  27.    
  28. }  



Java代码 复制代码
  1. package com.javaeye;   
  2.   
  3. import java.io.FileOutputStream;   
  4. import java.io.ObjectOutputStream;   
  5.   
  6. public class Main {   
  7.   
  8.     public static void main(String[] args); throws Exception {   
  9.          DomainObject obj = new DomainObject();;   
  10.          obj.setAge(29);;   
  11.          obj.setName("fankai");;   
  12.          FileOutputStream fos = new FileOutputStream("DomainObject");;   
  13.          ObjectOutputStream oos = new ObjectOutputStream(fos);;   
  14.          oos.writeObject(obj);;   
  15.          oos.close();;   
  16.          fos.close();;   
  17.      }   
  18.   
  19. }  
Java代码   收藏代码
  1. package com.javaeye;  
  2.   
  3. import java.io.FileOutputStream;  
  4. import java.io.ObjectOutputStream;  
  5.   
  6. public class Main {  
  7.   
  8.  public static void main(String[] args); throws Exception {  
  9.   DomainObject obj = new DomainObject();;  
  10.   obj.setAge(29);;  
  11.   obj.setName("fankai");;  
  12.   FileOutputStream fos = new FileOutputStream("DomainObject");;  
  13.   ObjectOutputStream oos = new ObjectOutputStream(fos);;  
  14.   oos.writeObject(obj);;  
  15.   oos.close();;  
  16.   fos.close();;  
  17.  }  
  18.   
  19. }  



DomainObject是我们准备序列化的类,在Main里面,我们new一个DomainObject的对象,然后赋值,最后把该对象序列化到一个硬盘文件中。 

然后使用一种支持二进制编辑器,例如UltraEdit打开这个文件,看看Java都对DomainObject序列化了哪些信息,你就什么都明白了。 

为了更方便观察,我使用Linux下面的strings去提取文本信息,输出为: 

robbin@linux:~> strings DomainObject 
com.javaeye.DomainObject 
ageL 
namet 
Ljava/lang/String;xp 
fankai 

这些信息很直观的告诉我们序列化都保存了些什么内容: 
1)对象的类型 
2)对象属性的类型 
3)对象属性的值 

并没有什么方法签名的信息,更不要说什么序列化方法了。 

然后我们再做一个试验,给DomainObject增加两个方法: 
Java代码 复制代码
  1. package com.javaeye;   
  2.   
  3. import java.io.Serializable;   
  4.   
  5. public class DomainObject  implements Serializable {   
  6.   
  7.     private String name;   
  8.        
  9.     private int age ;   
  10.   
  11.     public int getAge(); {   
  12.         return age;   
  13.      }   
  14.   
  15.     public void setAge(int age); {   
  16.         this.age = age;   
  17.      }   
  18.   
  19.     public String getName(); {   
  20.         return name;   
  21.      }   
  22.   
  23.     public void setName(String name); {   
  24.         this.name = name;   
  25.      }   
  26.        
  27.     public String toString(); {   
  28.         return "This is a serializable test!";   
  29.      }   
  30.        
  31.     public void doSomeWork(); {   
  32.          System.out.println("hello");;   
  33.      }   
  34. }  
Java代码   收藏代码
  1. package com.javaeye;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class DomainObject  implements Serializable {  
  6.   
  7.  private String name;  
  8.    
  9.  private int age ;  
  10.   
  11.  public int getAge(); {  
  12.   return age;  
  13.  }  
  14.   
  15.  public void setAge(int age); {  
  16.   this.age = age;  
  17.  }  
  18.   
  19.  public String getName(); {  
  20.   return name;  
  21.  }  
  22.   
  23.  public void setName(String name); {  
  24.   this.name = name;  
  25.  }  
  26.    
  27.  public String toString(); {  
  28.   return "This is a serializable test!";  
  29.  }  
  30.    
  31.  public void doSomeWork(); {  
  32.   System.out.println("hello");;  
  33.  }  
  34. }  


我们增加了toString方法和doSomeWork方法,按照你的理论,如果序列化方法的话,产生的文件体积必然增大。记录一下文件体积,92Byte,好了,删除,运行程序,生成了新的文件,看一下体积,还是92Byte! 

拿到Linux下面再提取一下字符串: 

robbin@linux:~> strings DomainObject 
com.javaeye.DomainObject 
ageL 
namet 
Ljava/lang/String;xp 
fankai 

完全一模一样! 

然后我们再做第三个试验,这次把DomainObject的两个属性以及相关方法删除掉: 
Java代码 复制代码
  1. package com.javaeye;   
  2.   
  3. import java.io.Serializable;   
  4.   
  5. public class DomainObject  implements Serializable {   
  6.   
  7.     public String toString(); {   
  8.         return "This is a serializable test!";   
  9.      }   
  10.        
  11.     public void doSomeWork(); {   
  12.          System.out.println("hello");;   
  13.      }   
  14. }  
Java代码   收藏代码
  1. package com.javaeye;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class DomainObject  implements Serializable {  
  6.   
  7.  public String toString(); {  
  8.   return "This is a serializable test!";  
  9.  }  
  10.    
  11.  public void doSomeWork(); {  
  12.   System.out.println("hello");;  
  13.  }  
  14. }  


修改Main类如下: 

Java代码 复制代码
  1. package com.javaeye;   
  2.   
  3. import java.io.FileOutputStream;   
  4. import java.io.ObjectOutputStream;   
  5.   
  6. public class Main {   
  7.   
  8.     public static void main(String[] args); throws Exception {   
  9.          DomainObject obj = new DomainObject();;   
  10.   
  11.          FileOutputStream fos = new FileOutputStream("DomainObject");;   
  12.          ObjectOutputStream oos = new ObjectOutputStream(fos);;   
  13.          oos.writeObject(obj);;   
  14.          oos.close();;   
  15.          fos.close();;   
  16.      }   
  17.   
  18. }  
Java代码   收藏代码
  1. package com.javaeye;  
  2.   
  3. import java.io.FileOutputStream;  
  4. import java.io.ObjectOutputStream;  
  5.   
  6. public class Main {  
  7.   
  8.  public static void main(String[] args); throws Exception {  
  9.   DomainObject obj = new DomainObject();;  
  10.   
  11.   FileOutputStream fos = new FileOutputStream("DomainObject");;  
  12.   ObjectOutputStream oos = new ObjectOutputStream(fos);;  
  13.   oos.writeObject(obj);;  
  14.   oos.close();;  
  15.   fos.close();;  
  16.  }  
  17.   
  18. }  



按照你的理论,如果序列化方法的话,我们必然应该在文件里面发现方法的签名信息,甚至方法里面包含的字符串,好了,再运行一遍,然后打开看一下吧!文件现在体积变成了45Byte,拿到Linux下面提取一下信息: 

robbin@linux:~> strings DomainObject 
com.javaeye.DomainObject 

只有对象的类型信息,再无其它东西了! 

请记住序列化机制只保存对象的类型信息,属性的类型信息和属性值,和方法没有什么关系,你就是给这个类增加10000个方法,序列化内容也不会增加任何东西,不要想当然的臆测自己不了解的知识,动手去做!

补充:

序列化在 Effective Java 中讲得很清楚啊, 一般认为只声明实现 implements 接口, 不提供自定义的序列化形式是不负责任的做法, 这样可能导致比较多的问题比如类的不同版本之间的兼容性, 看看 Effective Java 中的条目吧     谨慎地实现 Serialiable     
    为了继承而设计的类应该很少实现 Serialiable, 接口也应该很少会扩展它. 如果违反了这条规则, 则扩展这个类或者实现这个接口的程序员会背上沉重的负担. 
    
     若没有认真考虑默认序列化形式是否合适, 则不要接受这种形式 
   
    即使你确定了默认序列化形式是合适的, 通常你仍然要提供一个 readObject方法以保证约束关系和约束性    
    不管你选择了哪种序列化形式, 你都要为自己编写的每个可序列化的类声明一个显式的序列版本 UID (serialVersionUID)
 
从上面的结论看来, 实现了 Serialiable 接口并有比较好的实现的 OpenSource 代码几乎寥寥可数  , JDK 里的情况要好一些

 

分享到:
评论

相关推荐

    javaeye热点阅读

    4. Java、PHPRPC、Hessian、Burlap、AMF3、XML序列化的效率对比:这些是不同的数据序列化技术,对比它们在性能上的差异,对于优化服务端通信和数据传输有指导意义。 5. Effective Java Second Edition中文版:该书...

    JavaEye+技术架构

    JavaEye+技术架构,讲述java框架的应用

    使用 Eclipse 平台进行调试 - Java - JavaEye论坛

    使用 Eclipse 平台进行调试 - Java - JavaEye论坛

    javaeye被黑

    javaeye被黑 大家看看

    javaeye api [java httpclient版] 简单封装

    JavaEye API 的简单封装主要基于 Java 的 HttpClient 库,提供了更方便、易用的接口来执行 HTTP 请求。HttpClient 是一个成熟的 Java 库,用于执行 HTTP 协议的客户端请求,而 JavaEyeClient 则是对这个库进行了一层...

    JavaEye新闻月刊_-_2009年3月_-_总第13期

    JavaEye新闻月刊2009年3月第13期内容涉及了当时软件开发领域内的一系列重要话题,包括IBM拟收购Sun Microsystems公司的新闻报道、Java社区对此的看法以及各种编程语言、开发工具和技术的新动态。 首先,新闻月刊...

    JAva资源网站大全

    在IT领域,尤其是在软件开发行业中,Java作为一种广泛使用的编程语言,拥有庞大的学习资源和社区支持。对于初学者而言,找到合适的学习资源是掌握Java技能的关键一步。以下是从给定文件中整理出的Java资源网站大全,...

    javaeye月刊2008年4月 总第2期.pdf

    【JavaEye月刊2008年4月总第2期】主要涵盖了多个与Java相关的技术和行业动态。以下是对这些内容的详细解析: 1. **Spring创始人Rod Johnson再次发飙—“传统Java应用服务器正在没落”** Rod Johnson是Spring框架的...

    JavaEye论坛热点月报 总第7期

    2. **AJAX可视化编辑器** - 报告中提到了一个由用户分享的AJAX可视化编辑器项目,该编辑器拥有40多个图形界面控件,如标签、对话框、树型表格和时间线等,展示了AJAX在构建复杂交互式界面方面的潜力。 3. **Shoes**...

    Java基础知识总结大全

    ### Java基础知识总结大全 #### 一、Java内存区域划分 Java程序运行时,根据不同的功能需求,被划分为几个不同的内存区域,主要包括: ...这对于后续深入学习Android开发或其他基于Java的应用开发具有重要的意义。

    java基础知识总结(超级经典)

    #### 一、Java概述 - **起源与发展**:Java语言始于1991年Sun公司的James Gosling等人发起的Oak项目,最初目标是为了控制嵌入式设备,如有线电视交换盒和个人数字助理(PDA)。1994年,Oak语言被正式更名为Java。 - ...

    JAVA WEB 上傳(下載于JAVAEYE)

    在JAVA WEB开发中,上傳和下载功能是常见的需求,特别是在构建交互性强的Web应用程序时。这个主题主要涉及两个核心技术点:文件上传处理和服务器...理解并熟练掌握这些知识点,对于开发高质量的Java Web应用至关重要。

    测试JavaEye的PDF生成效果

    JavaEye可能是一个用于Java平台的开源库,它提供了将数据转换为PDF格式的功能,这对于创建报告、手册或其他需要打印或在线阅读的文档非常有用。在描述中提到的“博文链接”,虽然没有具体内容,但暗示了可能有更详细...

    java基础教程(强烈推荐)

    Java语言发展的历史中,Java的版本从Java 1.0开始,经历了Java 1.1、Java 1.2、Java 1.3、Java 1.4、Java 5、Java 6、Java 7、Java 8、Java 9等等,每个新版本的发布都带来了新的特性和改进。例如,Java 5版本中引入...

    Eclipse调试常用技巧 - Java综合 - Java - JavaEye论坛

    让想成为一个顶级程序员,学会调试异常是必不可少的。Eclipse调试常用技巧 -为你解决java程序中的出现的异常。

Global site tag (gtag.js) - Google Analytics