天天看点

JAVA序列化/反序列化与单例

单例设计类:

JAVA序列化/反序列化与单例

package com.test.singleton;  

import java.io.ioexception;  

import java.io.objectstreamexception;  

import java.io.serializable;  

public class singleton implements serializable{  

    /** 

     *  

     */  

    private static final long serialversionuid = 768457893059530646l;  

    private singleton(){  

        system.out.println("here...");  

        //避免反射机制,导致的多例问题,通过反射机制仍然可以对私有构造函数进行操作  

        if(instance != null){  

            return;  

        }  

    }  

    private static final singleton instance = new singleton();  

    public static singleton getinstance(){  

        return instance;  

    public void readobject(java.io.objectinputstream in) throws ioexception, classnotfoundexception{  

        //  

     * 严格单例,确保remote instance不会干扰单例模式,避免在发序列化过程中对单例的影响. 

     * @return 

     * @throws objectstreamexception 

    public object readresolve() throws objectstreamexception{  

}  

JAVA序列化/反序列化与单例

///////////流方式:  

import java.io.file;  

import java.io.fileinputstream;  

import java.io.fileoutputstream;  

import java.io.objectinputstream;  

import java.io.objectoutputstream;  

public class serializecheckmain {  

    * @param args 

    */  

    public static void main(string[] args) throws exception{  

        // todo auto-generated method stub  

        singleton s1 = singleton.getinstance();  

        file file = new file("d:\\singletome.txt");  

        objectoutputstream oos = new objectoutputstream(new fileoutputstream(file));  

        oos.writeobject(s1);  

        oos.close();  

        objectinputstream ois = new objectinputstream(new fileinputstream(file));  

        singleton s2 = (singleton)ois.readobject();  

        system.out.println("hashcode 1 : " + s1.hashcode());  

        system.out.println("hashcode 2 : " + s2.hashcode());  

        system.out.println("equal : " + (s1 == s2));//打破单例  

JAVA序列化/反序列化与单例

//////////////////////反射方式:  

import java.lang.reflect.constructor;  

/** 

 * @author liuguanqing 

 *  反射机制,测试单例 

 */  

public class refletcheckmain {  

        constructor[] constructors = singleton.class.getdeclaredconstructors();  

        constructor<singleton> c = constructors[0];  

        c.setaccessible(true);  

        singleton s2 = c.newinstance(null);  

注意,序列化和反序列化,是java使用字节码技术生成对象,将不会执行构造器方法.

注意到在writereplace和readresolve,我们可以严格控制singleton的对象,在同一个jvm中完完全全只有唯一的对象,控制不让singleton对象产生副本.

JAVA序列化/反序列化与单例

package com.test.main;  

public class testserializable implements serializable{  

    private static final long serialversionuid = -1740221592194879964l;  

    private integer age;  

    private string name;  

    public testserializable(){  

        system.out.println("contrustor..");  

    public integer getage() {  

        return age;  

    public void setage(integer age) {  

        this.age = age;  

    public string getname() {  

        return name;  

    public void setname(string name) {  

        this.name = name;  

    private void writeobject(java.io.objectoutputstream out) throws ioexception{  

        system.out.println("writeobject");  

        out.writeint(this.age);  

        out.writeint(this.name.getbytes("utf8").length);  

        out.write(this.name.getbytes("utf8"));  

    private void readobject(java.io.objectinputstream in) throws ioexception, classnotfoundexception{  

        this.age = in.readint();  

        int chars = in.readint();  

        byte[] bytes = new byte[chars];  

        in.readfully(bytes);  

        this.name = new string(bytes,"utf8");  

        system.out.println("readobject");  

        system.out.println("readresolve");  

        return this;  

    public object writereplace() throws objectstreamexception{  

        system.out.println("writereplace");  

     * @param args 

        objectoutputstream oos = new objectoutputstream(new fileoutputstream("d:\\sss.txt"));  

        testserializable ss = new testserializable();  

        ss.setage(12);  

        ss.setname("zhangsan");  

        oos.writeobject(ss);  

        objectinputstream ois = new objectinputstream(new fileinputstream("d:\\sss.txt"));  

        testserializable ss2 = (testserializable)ois.readobject();  

        system.out.println(ss == ss2);  

        system.out.println(ss2.getname());  

        ois.close();  

        //////////执行结果  

        //contrustor..  

        //writereplace  

        //writeobject  

        //readobject  

        //readresolve  

        //false  

        //zhangsan  

JAVA序列化/反序列化与单例

//////////externalizable接口是serializable的子接口,不过此接口提供了两个特殊的扩展方法:  

    @override  

    public void writeexternal(objectoutput out) throws ioexception {  

        system.out.println("writeex");  

        out.writeint(50);  

    public void readexternal(objectinput in) throws ioexception,  

            classnotfoundexception {  

        system.out.println("readex");  

注意实现externalizable接口的类,在发序列化时,将会执行构造函数,因为对于流操作而言,此对象是有明确类型的(serializable接口是个标记接口).

而且,如果实现了writeexternal和readexternal,将不会在执行readobject和writeobject,因为此时这两个方法已经被"擦除".

对于java序列化和反序列化,被序列化的类中有关于serialversionuid会带来一些问题;

1) 如果你调整了class结构(比如新增/去除某个属性值,但是不能引入编译错误),但没有修改serialversionuid;那么在反序列化和序列化时不会带来异常,只是可能导致部分属性在get时为null.

2) 如果你调整了class结构,同时也修改了serialversionuid;如果序列化和反序列双方没有保持uid一致的话,将会直接导致反序列化异常.(java.io.invalidclassexception)

3) 如果你没有显式的声明serialversionuid,那么对于jvm而言,不同的class类结构(属性列表和方法列表)将会得出不同的uid;因此如果序列化双方不能保持一致的uid,仍然会带来问题.

原文链接:[http://wely.iteye.com/blog/2228826]