单例与序列化剖析:解决的三种方法

来源:互联网 发布:mac梦幻西游连接失败 编辑:程序博客网 时间:2024/06/06 07:14
 

false
com.webex.refactor.SingleModule@1a758cb
com.webex.refactor.SingleModule@10b30a7

 

可见单例在反序列化中不能保持单例。

正常情况下: 

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class SingleModule implements Serializable {

 private static final long serialVersionUID = -6320624173133283454L;

 public static SingleModule getInstance() {
  return new SingleModule();
 }

 private SingleModule() {

 }

}

public class SerializeTool {

 private static byte[] objectStore;
 private final static SingleModule originSingle;
 private static SingleModule newSingle;

 static {
  originSingle = SingleModule.getInstance();
 }

 private static void verifyResult() {
  // TODO Auto-generated method stub
  System.out.println(newSingle == originSingle);
  System.out.println(newSingle);
  System.out.println(originSingle);

 }

 private static void deserializeUtil() {
  ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
    objectStore);
  ObjectInputStream objectInputStream = null;

  try {
   objectInputStream = new ObjectInputStream(byteArrayInputStream);
   Object readObject = objectInputStream.readObject();
   newSingle = (SingleModule) readObject;

  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } finally {
   closeStream(objectInputStream);
   closeStream(byteArrayInputStream);
  }
 }

 private static void serializeUtil(SingleModule singleModule) {
  ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  ObjectOutputStream objectOutputStream = null;

  try {
   objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
   objectOutputStream.writeObject(singleModule);
   objectStore = byteArrayOutputStream.toByteArray();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } finally {
   closeStream(objectOutputStream);
   closeStream(byteArrayOutputStream);
  }
 }

 private static void closeStream(Closeable Stream) {
  if (Stream != null) {
   try {
    Stream.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }
 
 public static void main(String[] args) {
  serializeUtil(originSingle);
  deserializeUtil();
  verifyResult();
 }

}

 

解决方法有3种:

(1)将单例作为成员存在,反序列化对象再读成员变量

(2)定制readResolve(), 带有对象引用类型的所有实例域都必须声明transient,主要出于安全考虑。如果应用在final类中用,应设置为private,如果是类为非final,且其子类没有覆盖readResolve()那么会产生一个超类实例,可能以后导致ClassCastException;

public class Singleton implements java.io.Serializable {   
   public static Singleton INSTANCE = new Singleton();   
     
   protected Singleton() {   
      // Exists only to thwart instantiation.    
   

   
   private Object readResolve() {   
            return INSTANCE;    
     
  

(3)定义成单元素枚举:

public enum Elvis{

 INSTANCE

}

方法三是最好的方式。支持序列化,


原创粉丝点击