Java实现单例模式之饿汉式、懒汉式、枚举式,带测试。
生活随笔
收集整理的這篇文章主要介紹了
Java实现单例模式之饿汉式、懒汉式、枚举式,带测试。
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Java實現單例的3種普遍的模式,餓漢式、懶漢式、枚舉式。
具體代碼如下:
package com.lcx.mode;/*** * 餓漢式單例,不管以后用不用這個對象,我們一開始就創建這個對象的實例,* 需要的時候就返回已創建好的實例對象,所以比較饑餓,故此叫餓漢式單例。* @author **/ public class SingletonHanger {private static final SingletonHanger instance = new SingletonHanger();private SingletonHanger() {}public static SingletonHanger getInstance(){return instance;} } /*** 懶漢漢式單例,在需要單例對象的時候,才創建唯一的單例對象,以后再次調用,返回的也是第一創建的單例對象* 將靜態成員初始化為null,在獲取單例的時候才創建,故此叫懶漢式。* @author **/ class SingletonLazy{private static SingletonLazy instance = null;private SingletonLazy() {}/*** 此方法實現的單例,無法在多線程中使用,多線可以同時進入if方法,會導致生成多個單例對象。* @return*/public static SingletonLazy getInstance1(){if(instance==null){instance = new SingletonLazy();}return instance;}/*** 大家都會想到同步,可以同步方法實現多線程的單例* 但是這種方法不可取,嚴重影響性能,因為每次去取單例都要檢查方法,所以只能用同步代碼塊的方式實現同步。* @return*/public static synchronized SingletonLazy getInstance2(){if(instance==null){instance = new SingletonLazy();}return instance;}/*** 用同步代碼塊的方式,在判斷單例是否存在的if方法里使用同步代碼塊,在同步代碼塊中再次檢查是否單例已經生成,* 這也就是網上說的 雙重檢查加鎖的方法* @return*/public static synchronized SingletonLazy getInstance3(){if(instance==null){synchronized (SingletonLazy.class) {if(instance==null){instance = new SingletonLazy();}}}return instance;} } /*** * 使用枚舉實現單例模式,也是Effective Java中推薦使用的方式* 根據具體情況進行實例化,對枚舉不熟悉的同學,可以參考我的博客 JAVA 枚舉類的初步理解。* 它的好處:更加簡潔,無償提供了序列化機制,絕對防止多次實例化,即使面對復雜的序列和反射攻擊。* @author **/ enum SingletionEnum{SingletionEnum("單例的枚舉方式");private String str ;private SingletionEnum(String str){this.setStr(str);}public String getStr() {return str;}public void setStr(String str) {this.str = str;}}以上的單例模式就不測試,大家可以去測試,判斷對象的hashcode是否一致來判斷是否為同一個對象。
惡漢式、懶漢式的方式還不能防止反射來實現多個實例,通過反射的方式,設置ACcessible.setAccessible方法可以調用私有的構造器,可以修改構造器,讓它在被要求創建第二個實例的時候拋出異常。
其實這樣還不能保證單例,當序列化后,反序列化是還可以創建一個新的實例,在單例類中添加readResolve()方法進行防止。
代碼如下:
package com.lcx.mode;import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;/*** 懶漢漢式單例,在需要單例對象的時候,才創建唯一的單例對象,以后再次調用,返回的也是第一創建的單例對象* 將靜態成員初始化為null,在獲取單例的時候才創建,故此叫懶漢式。* @author **/ public class Singleton implements Serializable{/*** */private static final long serialVersionUID = -5271537207137321645L;private static Singleton instance = null;private static int i = 1;private Singleton() {/*** 防止反射攻擊,只運行調用一次構造器,第二次拋異常*/if(i==1){i++;}else{throw new RuntimeException("只能調用一次構造函數");}System.out.println("調用Singleton的私有構造器");}/*** 用同步代碼塊的方式,在判斷單例是否存在的if方法里使用同步代碼塊,在同步代碼塊中再次檢查是否單例已經生成,* 這也就是網上說的 雙重檢查加鎖的方法* @return*/public static synchronized Singleton getInstance(){if(instance==null){synchronized (Singleton.class) {if(instance==null){instance = new Singleton();}}}return instance;}/*** * 防止反序列生成新的單例對象,這是effective Java 一書中說的用此方法可以防止,具體細節我也不明白* @return*/private Object readResolve(){return instance;}public static void main(String[] args) throws Exception {test1();test2();}/*** 測試 反序列 仍然為單例模式* @throws Exception*/public static void test2() throws Exception{Singleton s = Singleton.getInstance();ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("E:\\Singleton.txt")));objectOutputStream.writeObject(s);ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("E:\\Singleton.txt")));Object readObject = objectInputStream.readObject();Singleton s1 = (Singleton)readObject;System.out.println("s.hashCode():"+s.hashCode()+",s1.hashCode():"+s1.hashCode());objectOutputStream.flush();objectOutputStream.close();objectInputStream.close();}/*** 測試反射攻擊* @throws Exception*/public static void test1(){Singleton s = Singleton.getInstance();Class c = Singleton.class;Constructor privateConstructor;try {privateConstructor = c.getDeclaredConstructor();privateConstructor.setAccessible(true);privateConstructor.newInstance();} catch (Exception e) {e.printStackTrace();}} }驗證反射攻擊結果:
如果不添加readResolve方法的結果:
添加readResolve方法的結果:
總結
以上是生活随笔為你收集整理的Java实现单例模式之饿汉式、懒汉式、枚举式,带测试。的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Visual paradigm Db A
- 下一篇: JAVA中整数类型数据溢出问题研究