1. 程式人生 > >java單例模式之readResolve()

java單例模式之readResolve()

不考慮反射這種極端情況,還有一種情況會破壞單例模式。
序列化,反序列化!

package cp2;

import java.io.Serializable;
import java.util.Objects;

/**
 * Created by dubby on 16/3/25.
 */
public class SerSingleton implements Serializable {
    String name;
    private SerSingleton(){
        System.out.println("Singleton is creating");
    }

    private
static SerSingleton instance = new SerSingleton(); public static SerSingleton getInstance(){ return instance; } public static void createString(){ System.out.println("create string in singleton"); } }

測試程式碼:

import cp2.SerSingleton;
import junit.framework.Assert;
import
org.junit.Test; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; /** * Created by dubby on 16/3/25. */ public class SerSingletonTest { @Test public void test() throws Exception{ SerSingleton s1 = null
; SerSingleton s = SerSingleton.getInstance(); FileOutputStream fos = new FileOutputStream("a.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s); oos.flush(); oos.close(); FileInputStream fis = new FileInputStream("a.txt"); ObjectInputStream ois = new ObjectInputStream(fis); s1 = (SerSingleton) ois.readObject(); Assert.assertEquals(s,s1); } }

結果:

junit.framework.AssertionFailedError: 
Expected :cp2.SerSingleton@7ab2bfe1
Actual   :cp2.SerSingleton@497470ed
   <Click to see difference>

問題來了,怎麼解決呢?jdk其實預料到這種情況了。
解決方法:加入readResolve()

在jdk中ObjectInputStream的類中有readUnshared()方法,上面詳細解釋了原因。我簡單描述一下,那就是如果被反序列化的物件的類存在readResolve這個方法,他會呼叫這個方法來返回一個“array”(我也不明白),然後淺拷貝一份,作為返回值,並且無視掉反序列化的值,即使那個位元組碼已經被解析。
所以,完整的單例模式是:

package cp2;

import java.io.Serializable;
import java.util.Objects;

/**
 * Created by dubby on 16/3/25.
 */
public class SerSingleton implements Serializable {
    String name;
    private SerSingleton(){
        System.out.println("Singleton is creating");
    }

    private static SerSingleton instance = new SerSingleton();

    public static SerSingleton getInstance(){
        return instance;
    }

    public static void createString(){
        System.out.println("create string in singleton");
    }

    private Object readResolve(){
        System.out.println("read resolve");
        return instance;
    }
}