Java設計模式之單例模式最佳實踐

Java設計模式之單例模式最佳實踐

//新建枚舉類
public enum EnumInstance  {
    INSTANCE;
    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumInstance getInstance(){
        return INSTANCE;
    }
}

//調用
   EnumInstance instance=EnumInstance.getInstance();
    try {
            //將對象寫入文件
            ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("singleton_file"));
            oos.writeObject(instance);
            File file=new File("singleton_file");
            //從文件中獲取對象
            ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
            EnumInstance instance2= (EnumInstance) ois.readObject();
            //比較兩個對象是否相同
            System.out.println(instance);
            System.out.println(instance2);
            System.out.println(instance == instance2);
        } catch (Exception e) { e.printStackTrace(); }


//結果
INSTANCE
INSTANCE
true

//結論:反序列化後的對象與之前的對象相同。


//再看一下data對象是否相同
        EnumInstance instance=EnumInstance.getInstance();
        //設置data
        instance.setData(new Object());
        try {
            //將對象寫入文件
            ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("singleton_file"));
            oos.writeObject(instance);
            File file=new File("singleton_file");
            //從文件中獲取對象
            ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
            EnumInstance instance2= (EnumInstance) ois.readObject();
            //比較兩個對象是否相同
            System.out.println(instance.getData());
            System.out.println(instance2.getData());
            System.out.println(instance.getData() == instance2.getData());
        } catch (Exception e) { e.printStackTrace(); }

//結果
java.lang.Object@378bf509
java.lang.Object@378bf509
true

下面分析一下源碼,爲什麼枚舉類不會破壞單例? 

EnumInstance instance2= (EnumInstance) ois.readObject();

private Object readObject0(boolean var1) throws IOException {
            
        case 126:
                var4 = this.checkResolve(this.readEnum(var1));

}


private Enum<?> readEnum(boolean var1) throws IOException{
     String var5 = this.readString(false);
                Enum var6 = null;
                Class var7 = var2.forClass();
                if (var7 != null) {
                    try {
                //直接返回枚舉類裏面的對象,因此序列化不會破壞單例模式
                        Enum var8 = Enum.valueOf(var7, var5);                       
                    } 
                }
}


下面看看能否通過反射獲取構造器來實例化對象。

//首先通過單例模式獲取對象
        EnumInstance instance=EnumInstance.getInstance();
        try {
            Class objectClass=EnumInstance.class;
            //通過反射獲取構造器,這裏需要傳入參數
            Constructor constructor=objectClass.getDeclaredConstructor(String.class,int.class);
            //修改構造器的權限
            constructor.setAccessible(true);
            //通過構造器獲取新的對象,這裏需要傳入參數
            EnumInstance newInstance= (EnumInstance) constructor.newInstance("crook",888);
            //比較兩個對象是否相同
            System.out.println(instance);
            System.out.println(newInstance);
            System.out.println(instance == newInstance  );
        } catch (Exception e) {
            e.printStackTrace();
        }


//結果:不能通過反射獲取構造器來實例化對象。
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
	at com.zk.javatest.singleton.lazy_singleton.Test.main(Test.java:88)

 下面推薦一個反編譯工具jad,反編譯枚舉類到底發生了什麼?

jad下載地址:

https://varaneckas.com/jad/

 下載完成後,解壓,然後將EnumInstance.class文件複製到解壓後的文件夾,如下圖:

 

在該文件夾下打開終端,執行命令:

 

jad EnumInstance.class

然後就會生產反編譯後的文件EnumInstance.jad,用vim或者sublime打開該文件。

//反編譯後的類
public final class EnumInstance extends Enum
{

    public static EnumInstance[] values()
    {
        return (EnumInstance[])$VALUES.clone();
    }

    public static EnumInstance valueOf(String name)
    {
        return (EnumInstance)Enum.valueOf(com/zk/javatest/singleton/lazy_singleton/EnumInstance, name);
    }

    private EnumInstance(String s, int i)
    {
        super(s, i);
    }

    public Object getData()
    {
        return data;
    }

    public void setData(Object data)
    {
        this.data = data;
    }

    public static EnumInstance getInstance()
    {
        return INSTANCE;
    }

    public static final EnumInstance INSTANCE;
    private Object data;
    private static final EnumInstance $VALUES[];

    static 
    {
        INSTANCE = new EnumInstance("INSTANCE", 0);
        $VALUES = (new EnumInstance[] {
            INSTANCE
        });
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章