這個問題的答案引用Jon Skeet 回答
首先明確的是兩個都是線程安全的灿巧,兩者間最大的區(qū)別就是單例可以實現(xiàn)接口(Ps: 或者繼承基類蜡歹,雖然這種方式很少見),所以你可以當成一個問題的兩種不同實現(xiàn)方式。實際上弟孟,首先Singleton是對象(實例),而用static修飾class的時候是方法集合,其次單例是一種設計思想。 看代碼:
```
publicclassSingleton {privatestaticSingleton s =null;privateSingleton() { }publicstaticSingletongetInstance() {if(s ==null) s =newSingleton();returns;
}publicvoidfun() {/* some code */}publicstaticvoidstaticfun() {/* some code */}publicstaticvoidmain(String[] args) {
Singleton.getInstance().fun();
Singleton.staticfun();
}
}
```
1. 首先明確一下扎酷,靜態(tài)成員并不是什么程序加載時創(chuàng)建并初始化的,而是類加載時進行遏匆。類的加載是第一次真正用到它的時候(拿類new實例或調用它的靜態(tài)方法)進行的法挨,而這個加載過程需要將 class 文件中構成類的靜態(tài)和實例方法等類的成員的字節(jié)碼指令一同加載到內存中,而后要為靜態(tài)域分配存儲空間并使用靜態(tài)塊對其進行初始化(如果有的話)幅聘。在上面例子中凡纳,類加載后,所有成員(包括fun和staticfun)的字節(jié)碼指令均在內存中了帝蒿,隨時等待著調用荐糜,并且靜態(tài)域 s 所占用的存儲空間也用空引用初始化好了。
2. 從內存上來看,當?shù)谝淮握{用 getInstance() 方法時會創(chuàng)建此類的唯一實例(所謂的單例出現(xiàn))暴氏,其實也可以在聲明 s 時 new 它的唯一實例延塑,將實例化延后是為了避免類加載后實例使用前內存的浪費。
3. 靜態(tài)方法線程是安全的答渔,所謂線程安不安全是指當多個線程同時操作一個對象(通過調用它的實例方法)時是否會造成對象內部狀態(tài)的破壞关带,而靜態(tài)方法不是用來對實例進行操作的,所以一般不用考慮線程同步沼撕。如果在靜態(tài)方法中讀寫文件宋雏,此時如果多個線程同時通過調用此靜態(tài)方法對文件操作肯定會造成文件內容的破壞,但這不是線程沒同步造成的务豺,因為沒有對象的狀態(tài)被破壞磨总。但可以利用線程同步機制防止上面情況的發(fā)生。
4.從生命周期上來看冲呢,靜態(tài)方法的類會在代碼編譯的時候就被加載舍败,靜態(tài)方法中產(chǎn)生的對象,會隨著靜態(tài)方法執(zhí)行完畢而釋放掉敬拓,而且執(zhí)行類中的靜態(tài)方法時邻薯,不會實例化靜態(tài)方法所在的類。如果用單例模式, 產(chǎn)生的那一個唯一的實例乘凸,會一直在內存中厕诡,不會被GC清除的(原因是靜態(tài)的屬性變量不會被GC清除),除非整個應用退出了JVM (所以實際應用中更多的是靜態(tài)方法中獲取單例)
5. 單例模式是利用唯一的實例保存系統(tǒng)的狀態(tài)营勤,提供的實例方法也是為了對這個唯一的實例進行操作灵嫌,而靜態(tài)方法多是一些工具方法,Math 類中的靜態(tài)方法就是一個典型的例子葛作,如果僅僅是想不自己創(chuàng)建類的實例就可以調用到某些方法來完成一定的操作寿羞,那完全沒必要也不應該使用單例模式。
6. 從執(zhí)行效率上看: 靜態(tài)方法與實例方法赂蠢,在加載時機和占用內存上绪穆,靜態(tài)方法和實例方法是一樣的,在類型第一次被使用時加載虱岂。調用的速度基本上沒有差別玖院。 但是從日志打印來看,個人感覺還是靜態(tài)方法在執(zhí)行效率上快一點第岖。
6. 靜態(tài)方法是面向過程的难菌,而非面向對象的編程思想