博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
序列化与自定义序列化
阅读量:4106 次
发布时间:2019-05-25

本文共 12686 字,大约阅读时间需要 42 分钟。

说java的序列化一般都是Serializable接口,今天不仅是这部分内容。

第一部分 Serializable接口

首先说一下Serializable接口,类需要实现这个接口,但是需要注意几点

1.如果这个类是可序列化的,那么他的子类也是可以序列化的。

2.如果这个类是可序列化的,他的父类如果没有实现Serializable接口,那么父类的属性不会被序列化,除非父类也实现了Serializable接口。

3.关于类的静态变量,序列化和反序列化不会影响类静态变量的值。

4.Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

5.关于类的serialVersionUID 的问题,在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;而在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

/**  * @Title: SerializableTest.java  * @Package com.digital.base.serializable  * @Description: TODO(用一句话描述该文件做什么)   * @date 2018年7月9日  * @version V1.0  */  package com.digital.base.serializable;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;/**  * @ClassName: SerializableTest  * @Description: TODO(这里用一句话描述这个类的作用)  * @author liucgc  * @date 2018年7月9日  *    */public class SerializableTest {	public static void main(String[] args) throws Exception {		FileOutputStream fos = new FileOutputStream("temp.out");		ObjectOutputStream oos = new ObjectOutputStream(fos);		TestObject testObject = new TestObject();		testObject.staticValue=500;		testObject.parentValue=200;//		TestObject.staticValue=5000;		System.out.println(testObject.staticValue);		System.out.println("parentValue is "+testObject.parentValue);		oos.writeObject(testObject);		oos.flush();		oos.close();		TestObject.staticValue=5000;		 		FileInputStream fis = new FileInputStream("temp.out");		ObjectInputStream ois = new ObjectInputStream(fis);		TestObject deTest = (TestObject) ois.readObject();		System.out.println(deTest.testValue);		System.out.println("parentValue is "+deTest.parentValue);		System.out.println(deTest.innerObject.innerValue);		System.out.println(deTest.staticValue);		}		}	 		class Parent //implements Serializable 		{		 		private static final long serialVersionUID = -4963266899668807475L;		 		public int parentValue = 100;		}		 		class InnerObject implements Serializable {		 		private static final long serialVersionUID = 5704957411985783570L;		 		public int innerValue = 200;		}		 		class TestObject extends Parent implements Serializable {		 		private static final long serialVersionUID = -3186721026267206914L;		 		public int testValue = 300;				public static int staticValue=50;		 		public InnerObject innerObject = new InnerObject();		}

第二部分 自定义序列化之Serializable

自定义序列化是由ObjectInput/OutputStream在序列化/反序列化时候通过反射检查该类是否存在以下方法(0个或多个):执行顺序从上往下,序列化调用1和2,反序列调用3和4;transient关键字当某个字段被声明为transient后,默认序列化机制就会忽略该字段。

1.Object writeReplace() throws ObjectStreamException;可以通过此方法修改序列化的对象
2.void writeObject(java.io.ObjectOutputStream out) throws IOException; 方法中调用defaultWriteObject() 使用writeObject的默认的序列化方式,除此之外可以加上一些其他的操作,如添加额外的序列化对象到输出:out.writeObject("XX")
3.void readObject(java.io.ObjectInputStream in) throws Exception; 方法中调用defaultReadObject()使用readObject默认的反序列化方式,除此之外可以加上一些其他的操作,如读入额外的序列化对象到输入:in.readObject()

4.Object readResolve() throws ObjectStreamException;可以通过此方法修改返回的对象。

自定义的 writeReplace、writeObject、readResolve 和 readObject 方法可以允许用户控制序列化的过程,下面的例子中模拟了对password字段加密。

/**  * @Title: Personser.java  * @Package com.digital.base.serializable  * @Description: TODO(用一句话描述该文件做什么)  * @date 2018年7月9日  * @version V1.0  */  package com.digital.base.serializable;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectInputStream.GetField;import java.io.ObjectOutputStream;import java.io.ObjectOutputStream.PutField;import java.io.Serializable;import java.util.Date;/**  * @ClassName: Personser  * @Description: TODO(这里用一句话描述这个类的作用)  * @author liucgc  * @date 2018年7月9日  *    */public class Personser implements Serializable {	private String code;	private String password="pass";	private Date createDate;	/**  	* @Title: main  	* @Description: TODO(这里用一句话描述这个方法的作用)  	* @param @param args    参数  	* @return void    返回类型  	* @throws  	*/	public static void main(String[] args) {	    try {	        ObjectOutputStream out = new ObjectOutputStream(	                new FileOutputStream("result.obj"));	        Personser per=new Personser();	        per.setPassword("password123");	        out.writeObject(per);	        out.close();	 	        ObjectInputStream oin = new ObjectInputStream(new FileInputStream(	                "result.obj"));	        Personser t = (Personser) oin.readObject();	        System.out.println("解密后的字符串:" + t.getPassword());	        oin.close();	    } catch (FileNotFoundException e) {	        e.printStackTrace();	    } catch (IOException e) {	        e.printStackTrace();	    } catch (ClassNotFoundException e) {	        e.printStackTrace();	    }	}	/**	 * @return the code	 */	public String getCode() {		return code;	}	/**	 * @param code the code to set	 */	public void setCode(String code) {		this.code = code;	}	/**	 * @return the password	 */	public String getPassword() {		return password;	}	/**	 * @param password the password to set	 */	public void setPassword(String password) {		this.password = password;	}	/**	 * @return the createDate	 */	public Date getCreateDate() {		return createDate;	}	/**	 * @param createDate the createDate to set	 */	public void setCreateDate(Date createDate) {		this.createDate = createDate;	}	private void writeObject(ObjectOutputStream out) {	    try {	        PutField putFields = out.putFields();	        System.out.println("原密码:" + password);	        password = enCode(password);//模拟加密	        putFields.put("password", password);	        System.out.println("加密后的密码" + password);	        out.writeFields();	    } catch (IOException e) {	        e.printStackTrace();	    }	}	private void readObject(ObjectInputStream in) {	    try {	        GetField readFields = in.readFields();	        	        Object object = readFields.get("password", "encryption");	        System.out.println("要解密的字符串:" + object.toString());	        password=object.toString();	        password=deCode(password);//模拟解密,需要获得本地的密钥	    } catch (IOException e) {	        e.printStackTrace();	    } catch (ClassNotFoundException e) {	        e.printStackTrace();	    }	}	public String enCode(String pass) {				if("password123".equals(pass)) {			return "encryption";		}		return "error";	}	public String deCode(String pass) {				if("encryption".equals(pass)) {			return "password123";		}		return "error";	}}

单例模式的类实现序列化接口,若使用默认的序列化策略,则在反序列化返回的对象创建了新的对象,破坏了单例模式,面试扩展:如果一个类是单例的,那么如何能再创建该类一个新的对象。

private Object readResolve() throws ObjectStreamException {        System.out.println("4 read resolve start");        return PersonSingleton.getInstance();//不管序列化的操作是什么,返回的都是本地的单例对象    }

第三部分 自定义之 Externalizable接口

此种实现方法需要注意的两点,

1.类必须存在一个pulic的无参数构造方法。

2.反序列化时的字段属性需要与序列化时一致,否则值顺序错乱。

/**  * @Title: Personextern.java  * @Package com.digital.base.serializable  * @Description: TODO(用一句话描述该文件做什么)  * @author liucgc  * @date 2018年7月9日  * @version V1.0  */  package com.digital.base.serializable;import java.io.Externalizable;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInput;import java.io.ObjectInputStream;import java.io.ObjectOutput;import java.io.ObjectOutputStream;import java.util.Date;/**  * @ClassName: Personextern  * @Description: TODO(这里用一句话描述这个类的作用)  * @author liucgc  * @date 2018年7月9日  *    */public class Personextern implements Externalizable {	private String code;	private String password="pass";	private Date createDate;	public Personextern() {		System.out.println("Personextern constructor1");	}	public Personextern(String code,String password,Date createDate) {		this.code=code;		this.password=password;		this.createDate=createDate;		System.out.println("Personextern constructor2");	}	public void writeExternal(ObjectOutput out) throws IOException {		// TODO Auto-generated method stub		out.writeObject(code);		out.writeObject(password);		out.writeObject(createDate);	}	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {				code=(String) in.readObject();		password=(String) in.readObject();		createDate=(Date)in.readObject();	}	/**	 * @throws IOException   	* @Title: main  	* @Description: TODO(这里用一句话描述这个方法的作用)  	* @param @param args    参数  	* @return void    返回类型  	* @throws  	*/	public static void main(String[] args) throws IOException {		FileOutputStream fos=null;        ObjectOutputStream oos=null;        FileInputStream fis=null;        ObjectInputStream ois=null;        try {	        Personextern per=new Personextern();	        per.setPassword("password123");	        per.setCode("123123");            fos=new FileOutputStream(new File("E://javanewlskd.txt"));            oos=new ObjectOutputStream(fos);            oos.writeObject(per);        } catch (FileNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IOException e) {			// TODO Auto-generated catch block			e.printStackTrace();		} finally {            if(oos!=null) {                oos.close();            }        }                try {            fis=new FileInputStream(new File("E://javanewlskd.txt"));            ois=new ObjectInputStream(fis);            System.out.println("反序列化之后,readObject");            Personextern per=(Personextern)ois.readObject();            System.out.println(per);        } catch(Exception e) {            e.printStackTrace();        } finally {            if(ois!=null) {                ois.close();            }        }        	}	@Override	public String toString() {		return "Personextern [code=" + code + ", password=" + password + ", createDate=" + createDate + "]";	}	/**	 * @return the code	 */	public String getCode() {		return code;	}	/**	 * @param code the code to set	 */	public void setCode(String code) {		this.code = code;	}	/**	 * @return the password	 */	public String getPassword() {		return password;	}	/**	 * @param password the password to set	 */	public void setPassword(String password) {		this.password = password;	}	/**	 * @return the createDate	 */	public Date getCreateDate() {		return createDate;	}	/**	 * @param createDate the createDate to set	 */	public void setCreateDate(Date createDate) {		this.createDate = createDate;	}}

第四部分 性能对比

/**  * @Title: TestPerformance.java  * @Package com.digital.base.serializable  * @Description: TODO(用一句话描述该文件做什么)  * @author liucgc  * @date 2018年7月9日  * @version V1.0  */  package com.digital.base.serializable;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;/**  * @ClassName: TestPerformance  * @Description: TODO(这里用一句话描述这个类的作用)  * @author liucgc  * @date 2018年7月9日  *    */public class TestPerformance {	/**	 * @throws IOException   	* @Title: main  	* @Description: TODO(这里用一句话描述这个方法的作用)  	* @param @param args    参数  	* @return void    返回类型  	* @throws  	*/	public static void main(String[] args) throws IOException {        long start =  System.currentTimeMillis();          int count=10000;        start =  System.currentTimeMillis();        setSerializableObject(count);          System.out.println("java原生序列化时间:" + (System.currentTimeMillis() - start) + " ms" );            start =  System.currentTimeMillis();          getSerializableObject(count);          System.out.println("java原生反序列化时间:" + (System.currentTimeMillis() - start) + " ms");                start =  System.currentTimeMillis();        setSerializableObjectExt(count);          System.out.println("java Externalizable序列化时间:" + (System.currentTimeMillis() - start) + " ms" );            start =  System.currentTimeMillis();          getSerializableObjectExt(count);          System.out.println("java Externalizable反序列化时间:" + (System.currentTimeMillis() - start) + " ms"); 	}	/**  	* @Title: getSerializableObject  	* @Description: TODO(这里用一句话描述这个方法的作用)  	* @param @param count    参数  	* @return void    返回类型  	* @throws  	*/  	private static void getSerializableObject(int count) {	    try {	        ObjectInputStream oin = new ObjectInputStream(new FileInputStream(	                "result.obj"));	        for(int i=0;i

自定义序列化效率更低一些。

java Externalizable序列化时间:214 msjava Externalizable反序列化时间:255 msjava原生序列化时间:85 msjava原生反序列化时间:166 msjava原生序列化时间:106 msjava原生反序列化时间:164 msjava Externalizable序列化时间:196 msjava Externalizable反序列化时间:229 ms

参考网页相关地址

https://www.cnblogs.com/yoohot/p/6019767.html微笑https://www.cnblogs.com/chenfei0801/archive/2013/04/06/3002146.html

http://www.cnblogs.com/dukc/p/4817822.html

你可能感兴趣的文章
ISP和IAP两种编程方式有何区别?
查看>>
CListCtrl列表中,改写几列的文字颜色
查看>>
MFC CListCtrl 使用介绍
查看>>
vc workspace不能显示类视图/工程文件视图/资源视图
查看>>
铝电解电容品牌排行榜
查看>>
电感品牌
查看>>
WinAVR MakeFile分析
查看>>
堆区和栈区的区别
查看>>
画笔的异或模式
查看>>
STUDIO到IAR
查看>>
GCC出现warning: integer constant is too large for 'long' type"
查看>>
winAVR 全局变量volatile
查看>>
OP AMP - 单电源对运算放大器的影响
查看>>
如何正确选择AD/DA器件
查看>>
IAP ISP 区别
查看>>
STM32 注意的地方
查看>>
PCB Layout 中的直角走线、差分走线和蛇形线
查看>>
layout中蛇形线和差分线的使用
查看>>
ppm/℃是什么单位?什么意思?
查看>>
Java通过引用js脚本引擎实现精确计算
查看>>