zoukankan      html  css  js  c++  java
  • java序列化进阶

          在java中,通常情况下,一旦一个程序运行结束,生成的对象也会消失。如果想永久的保存对象,可以将对象序列化,在需要的时候在进行反序列化。java类实现序列化的方法非常简单,只需要实现Serializable即可。Serializable是一个接口,没有任何的方法。序列化只需要构建一个ObjectOutputStream,然后执行ObjectOutputStream的writeObject()方法。反序列化就是执行相反的方法,构建一个ObjectInputStream,然后执行readObject()方法。
     
     
    下面的实例中都会用到一个test的方法,如下
    package com.my.web.server;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    import com.my.web.model.UserInfo;
    
    /**
     * 序列化ser
     * @author zhangxiuxiu
     *
     */
    public class SerializableSer {
    	
    	public static void main(String[] args) throws IOException, ClassNotFoundException {
    		SerializableSer ser = new SerializableSer();
    		ser.serializable();
    		ser.deserialize();
    	}
    
    	/**
    	 * 序列化
    	 * @throws IOException 
    	 */
    	public void serializable() throws IOException{
    		UserInfo u = new UserInfo("1", "zxx");
    		u.setPassword("zxx");
    		File file = new File("userinfo.txt");
    		
    		file.createNewFile();
    		
    		//序列化的过程
    		FileOutputStream fileOutputStream = new FileOutputStream(file);
    		ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
    		objectOutputStream.writeObject(u);
    		objectOutputStream.flush();
    		objectOutputStream.close();
    		fileOutputStream.close();
    	}
    	
    	
    	/**
    	 * 反列化
    	 * @throws IOException 
    	 * @throws ClassNotFoundException 
    	 */
    	public void deserialize() throws IOException, ClassNotFoundException{
    		File file = new File("userinfo.txt");
    		
    		FileInputStream fis = new FileInputStream(file);
    		ObjectInputStream ois = new ObjectInputStream(fis);
    		
    		UserInfo ui = (UserInfo)ois.readObject();
    		System.out.println(ui.toString());
    		
    		ois.close();
    		fis.close();
    	}
    	
    	
    }
    

      

     
     
     
    一、实现Serializable
             一个类实现Serializable了之后就可以很容易的进行序列化和反序列化的操作。这里面需要注意的是,反序列的过程并没有执行model的默认构造方法,只是通过流的方式来生成一个model类。所以并不要求model类有无参的构造方法。
      下面的例子中,UserInfo这个model中没有无参的构造方法,但是可以正常的进行序列化和反序列化。反序列化的时候不会调用UserInfo的构造方法
             
    package com.my.web.model;
    
    import java.io.Externalizable;
    import java.io.IOException;
    import java.io.ObjectInput;
    import java.io.ObjectOutput;
    import java.io.Serializable;
    import java.sql.Date;
    
    public class UserInfo implements Serializable{
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = -7448507529918501715L;
    	private String id;
    	private String userName;
    	private Date date;
    	private transient String password;
    	
    	
    	
    	
    	public UserInfo(String id,String userName){
    		System.out.println("有参数的构造方法:"+id+"--------"+userName);
    		this.id = id;
    		this.userName = userName;
    	}
    	
    	public String getPassword() {
    		return password;
    	}
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	public Date getDate() {
    		return date;
    	}
    	public void setDate(Date date) {
    		this.date = date;
    	}
    	public String getId() {
    		return id;
    	}
    	public void setId(String id) {
    		this.id = id;
    	}
    	public String getUserName() {
    		return userName;
    	}
    	public void setUserName(String userName) {
    		this.userName = userName;
    	}
    
    	public String toString(){
    		return "id:"+id+";userName:"+userName+";password:"+password+";date:"+(date==null?"":date.getTime());
    	}
    	
    	
    	
    }
    

      

      执行上面的test方法,结果如下

    有参数的构造方法:1--------zxx
    id:1;userName:zxx;password:null;date:

      

      使用实现Serializable的方法进行序列化的时候,最好在model类中增加serialVersionUID的属性。如果model中没有该属性,在进行序列化的时候,会根据model中的属性、方法通过算法生成一个serialVersionUID。这样会存在一个问题:如果先将该model序列化到了一个文件中,然后中间修改了model中的属性,比如新增了一个属性,在用该文件中的流进行反序列化的时候,会出现一个错误,这是因为序列化和反序列的时候算法生成的serialVersionUID不一致。所以如果生成了一个固定的serialVersionUID,就可以正确进行反序列化。

         报错如下图:

    Exception in thread "main" java.io.InvalidClassException: com.my.web.model.UserInfo; local class incompatible: stream classdesc serialVersionUID = -7448507529918501715, local class serialVersionUID = 7932322403676295014
    

         

          model里面可以新增writeObject和readObject方法,注意这里是用的新增,不是重写,因为Serializable中是没有这两个方法的。如果新增了这两个方法,在进行序列化的时候会执writeObject这个方法,就会不去执行默认的序列化方法,如果需要执行默认的方法,只需要增加out.defaultWriteObject();即可。反序列过程有类似的ois.defaultReadObject();方法,具体事例见下图

         

    package com.my.web.model;
    
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.sql.Date;
    
    public class UserInfo implements Serializable{
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = -7448507529918501715L;
    	private String id;
    	private String userName;
    	private String password;
    	private Date date;
    	
    	
    	
    	private void writeObject(ObjectOutputStream out) throws IOException {
    		out.defaultWriteObject();
    		System.out.println("-----序列化-----");
    	}
    	
    	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
    		ois.defaultReadObject();
    		System.out.println("-----反序列化-----");
        }
    
    	
    	public UserInfo(String id,String userName){
    		System.out.println(id+"--------"+userName);
    		this.id = id;
    		this.userName = userName;
    	}
    
    	public Date getDate() {
    		return date;
    	}
    	public void setDate(Date date) {
    		this.date = date;
    	}
    	
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	public String getId() {
    		return id;
    	}
    	public void setId(String id) {
    		this.id = id;
    	}
    	public String getUserName() {
    		return userName;
    	}
    	public void setUserName(String userName) {
    		this.userName = userName;
    	}
    	
    	public String toString(){
    		return "id:"+id+";userName:"+userName+";password:"+password+";date:"+(date==null?"":date.getTime());
    	}
    	
    	
    }
    

      

      

      打印结果如下图

      

    1--------zxx
    -----序列化-----
    -----反序列化-----
    id:1;userName:zxx;password:zxx;date:

      当某个字段被声明为transient后,默认序列化机制就会忽略该字段。

    package com.my.web.model;
    
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.sql.Date;
    
    public class UserInfo implements Serializable{
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = -7448507529918501715L;
    	private String id;
    	private String userName;
    	private Integer age;
    	private String address;
    	private Date date;
    	private transient String password;
    	
    	
    	
    	private void writeObject(ObjectOutputStream out) throws IOException {
    		out.defaultWriteObject();
    		//just do it 
    		out.writeObject(password);
    		System.out.println("-----序列化-----");
    	}
    	
    	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
    		ois.defaultReadObject();
    		//just do it 
    		this.password = (String)ois.readObject();
    		System.out.println("-----反序列化-----");
        }
    
    	
    	public UserInfo(String id,String userName){
    		System.out.println(id+"--------"+userName);
    		this.id = id;
    		this.userName = userName;
    	}
    
    	
    	
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	public Date getDate() {
    		return date;
    	}
    	public void setDate(Date date) {
    		this.date = date;
    	}
    	public Integer getAge() {
    		return age;
    	}
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    	public String getAddress() {
    		return address;
    	}
    	public void setAddress(String address) {
    		this.address = address;
    	}
    	public String getId() {
    		return id;
    	}
    	public void setId(String id) {
    		this.id = id;
    	}
    	public String getUserName() {
    		return userName;
    	}
    	public void setUserName(String userName) {
    		this.userName = userName;
    	}
    	
    	public String toString(){
    		return "id:"+id+";userName:"+userName+";password:"+password+";date:"+(date==null?"":date.getTime());
    	}
    	
    	
    	
    }
    

      

       

      在上面的代码中,运行的结果如下

    1--------zxx
    -----序列化-----
    -----反序列化-----
    id:1;userName:zxx;password:zxx;date:

      但是,如果将just do it 下面红色的代码注释掉,运行的结果如下

    1--------zxx
    -----序列化-----
    -----反序列化-----
    id:1;userName:zxx;password:null;date:

      

    二、实现Externalizable

      通过实现Externalizable进行序列化和反序列的操作。这个在进行反序列的过程的时候,需要调用model的默认构造方法的,所以model一定要有public的无参构造方法,如果没有无参构造方法,在进行反序列化的时候,会提示错误。

    Exception in thread "main" java.io.InvalidClassException: com.my.web.model.UserInfo; no valid constructor
    

      有了无参数的构造方法,可以保证该model正常的进行序列化和反序列化,但是反序列化并不能取到值,必须在方法readExternal()中进行手动赋值

          

    package com.my.web.model;
    
    import java.io.Externalizable;
    import java.io.IOException;
    import java.io.ObjectInput;
    import java.io.ObjectOutput;
    import java.sql.Date;
    
    public class UserInfo implements Externalizable{
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = -7448507529918501715L;
    	private String id;
    	private String userName;
    	private Date date;
    	private transient String password;
    	
    	public UserInfo(){
    		System.out.println("无参数的构造方法");
    	}
    	
    	public UserInfo(String id,String userName){
    		System.out.println("有参数的构造方法:"+id+"--------"+userName);
    		this.id = id;
    		this.userName = userName;
    	}
    	
    	public String getPassword() {
    		return password;
    	}
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	public Date getDate() {
    		return date;
    	}
    	public void setDate(Date date) {
    		this.date = date;
    	}
    	public String getId() {
    		return id;
    	}
    	public void setId(String id) {
    		this.id = id;
    	}
    	public String getUserName() {
    		return userName;
    	}
    	public void setUserName(String userName) {
    		this.userName = userName;
    	}
    
    	public String toString(){
    		return "id:"+id+";userName:"+userName+";password:"+password+";date:"+(date==null?"":date.getTime());
    	}
    	
    
    	@Override
    	public void writeExternal(ObjectOutput out) throws IOException {
    		// TODO Auto-generated method stub
    		out.writeObject(id);
    		out.writeObject(userName);
    		
    	}
    
    
    	@Override
    	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    		// TODO Auto-generated method stub
    		this.id = (String)in.readObject();
    		this.userName = (String)in.readObject();
    	}
    	
    	
    	
    	
    }
    

      

      上述的执行结果

    有参数的构造方法:1--------zxx
    无参数的构造方法
    id:1;userName:zxx;password:null;date:
    

      如果把上面红色的代码注释掉,执行结果

    有参数的构造方法:1--------zxx
    无参数的构造方法
    id:null;userName:null;password:null;date:
    

      

     
  • 相关阅读:
    POJ3666 Making the Grade[动态规划]
    vector内部的实现1
    win32概述
    stl概述
    C++概要简介
    类的常量成员
    模板
    c11标准
    异常处理
    pak文件的打包和解包
  • 原文地址:https://www.cnblogs.com/hyzxx/p/7999250.html
Copyright © 2011-2022 走看看