static
那天我朋友問了我個問題,static和單例模式有什么區別,所以我覺得static可以講一下
他的問題是,把對象弄成static是不是就不變了
顯然,這是還沒弄清楚引用和對象的區別
其實存放在靜態區中的是引用,而不是對象。而對象是存放在堆中的。如果有這樣一句話
public static final Book book = new Book();
意思就是book這個引用,指向了這個new出來的對象。
static的引用和正常的引用有什么區別?
當你加載了這個類的時候(第一次使用這個類的時候會加載這個類到jvm),這個static引用會率先被加載。所以,當我們第一次調用Book.book的時候,這個靜態的book引用就會一直存放在靜態區里了(當fullGC回收整個類才會銷毀這個引用)。
而正常的引用,只能通過new出一個對象后才能使用,所以當對象被回收了,這個引用自然也回收了(而且非靜態引用如果是方法中的引用,會存放在函數的棧里;如果是對象的引用,會和對象一起存放在heap里)。
final
final定義了之后,你就必須在一開始就需要賦值,所以上面那行代碼就必須在一開始就賦值。而如果你想延遲加載,提高性能,那么就不可以用final。
單例模式
單例模式是如果實現的,就是通過調用這個類里的一個靜態方法,弄一個if語句判斷一下,如果有實例了,就返回這個實例,如果沒有,就創建這個實例。其實並沒有多大的技術含量。
第一種,最基本的思維。
public class Book { private static Book book = new Book(); private Book() {} public static Book getInstance() { if (book == null) { book = new Book(); } return book; } }
這里為什么要判空呢?因為你這個是靜態的,所以其他地方完全有Book.getInstance = null;的可能。
第二種,這里使用final,讓引用的指向不可變,這樣就不需要判空了
public class Book { private static final Book book = new Book(); private Book() {} public static Book getInstance() { return book; } }
第三種,延遲加載(線程不安全,假如有多個同時發現是空的,會創建出好多實例)
public class Book { private static Book book; private Book() {} public static Book getInstance() { if (book == null) { book = new Book(); } return book; } }
第四種,添加線程安全功能,加一個關鍵字就可以
public class Book { private static Book book; private Book() {} public static synchronized Book getInstance() { if (book == null) { book = new Book(); } return book; } }
這個方法在多線程下的工作表現很出色
第五種,規避不需要的同步,因為上面的同步范圍太大,有點浪費性能,在引用有指向的時候,是不需要同步的
public class Book { private static Book book; private Book() {} public static synchronized Book getInstance() { if (book == null) { synchronized (Book.class) { book = new Book(); } } return book; } }
第六種,靜態內部類
public class Book { private Book() {} public static synchronized Book getInstance() { return BookHolder.book; } private static class BookHolder { private static final Book book = new Book(); } }
第七種,枚舉單例
public class Book { private Book(){} public static Book getInstance() { return BookEnum.BOOK.getInstance(); } private static enum BookEnum { BOOK; private Book book; private BookEnum() { book = new Book(); } public Book getInstance() { return book; } } }
最優,但是枚舉這個東西可讀性不高