參考:https://blog.csdn.net/yyht800/article/details/54631357
參考:https://blog.csdn.net/baidu_41878679/article/details/82823145
-
什么是單例模式
單例模式指的是在應用整個生命周期內只能存在一個實例。單例模式是一種被廣泛使用的設計模式。他有很多好處,能夠避免實例對象的重復創建,減少創建實例的系統開銷,節省內存。 -
單例模式和靜態類的區別
首先理解一下什么是靜態類,靜態類就是一個類里面都是靜態方法和靜態field,構造器被private修飾,因此不能被實例化。Math類就是一個靜態類。
知道了什么是靜態類后,來說一下他們兩者之間的區別:
1)首先單例模式會提供給你一個全局唯一的對象,靜態類只是提供給你很多靜態方法,這些方法不用創建對象,通過類就可以直接調用;
2)單例模式的靈活性更高,方法可以被override,因為靜態類都是靜態方法,所以不能被override;
3)如果是一個非常重的對象,單例模式可以懶加載,靜態類就無法做到;
那么時候時候應該用靜態類,什么時候應該用單例模式呢?
首先如果你只是想使用一些工具方法,那么最好用靜態類,靜態類比單例類更快,因為靜態的綁定是在編譯期進行的。
如果你要維護狀態信息,或者訪問資源時,應該選用單例模式
還可以這樣說,當你需要面向對象的能力時(比如繼承、多態) 或者需要Init,判斷資源狀態時,選用單例類, 當你僅僅是提供一些方法時選用靜態接口類(雖然靜態類也可以做,但是會增加 很多條件判斷接口)。
首先明確的是兩個都是線程安全的,兩者間最大的區別就是單例可以實現接口
(Ps: 或者繼承基類,雖然這種方式很少見),所以你可以當成一個問題的兩種不同實現方式。實際上,首先Singleton是對象(實例),而用static修飾class的時候是方法集合,其次單例是一種設計思想。
1. 首先明確一下,靜態成員並不是什么程序加載時創建並初始化的,而是類加載時進行。類的加載是第一次真正用到它的時候(拿類new實例或調用它的靜態方法)進行的,而這個加載過程需要將 class 文件中構成類的靜態和實例方法等類的成員的字節碼指令一同加載到內存中,而后要為靜態域分配存儲空間並使用靜態塊對其進行初始化(如果有的話)。在上面例子中,類加載后,所有成員(包括fun和staticfun)的字節碼指令均在內存中了,隨時等待着調用,並且靜態域 s 所占用的存儲空間也用空引用初始化好了。
2. 從內存上來看,當第一次調用 getInstance() 方法時會創建此類的唯一實例(所謂的單例出現),其實也可以在聲明 s 時 new 它的唯一實例,將實例化延后是為了避免類加載后實例使用前內存的浪費。
. 靜態方法線程是安全的,所謂線程安不安全是指當多個線程同時操作一個對象(通過調用它的實例方法)時是否會造成對象內部狀態的破壞,而靜態方法不是用來對實例進行操作的,所以一般不用考慮線程同步。如果在靜態方法中讀寫文件,此時如果多個線程同時通過調用此靜態方法對文件操作肯定會造成文件內容的破壞,但這不是線程沒同步造成的,因為沒有對象的狀態被破壞。但可以利用線程同步機制防止上面情況的發生。
4.從生命周期上來看,靜態方法的類會在代碼編譯的時候就被加載,靜態方法中產生的對象,會隨着靜態方法執行完畢而釋放掉,而且執行類中的靜態方法時,不會實例化靜態方法所在的類。如果用單例模式, 產生的那一個唯一的實例,會一直在內存中,不會被GC清除的(原因是靜態的屬性變量不會被GC清除),除非整個應用退出了JVM (所以實際應用中更多的是靜態方法中獲取單例)
5. 單例模式是利用唯一的實例保存系統的狀態,提供的實例方法也是為了對這個唯一的實例進行操作,而靜態方法多是一些工具方法,Math 類中的靜態方法就是一個典型的例子,如果僅僅是想不自己創建類的實例就可以調用到某些方法來完成一定的操作,那完全沒必要也不應該使用單例模式。
6. 從執行效率上看: 靜態方法與實例方法,在加載時機和占用內存上,靜態方法和實例方法是一樣的,在類型第一次被使用時加載。調用的速度基本上沒有差別。 但是從日志打印來看,個人感覺還是靜態方法在執行效率上快一點。 6. 靜態方法是面向過程的,而非面向對象的編程思想