單例模式(一)static、final和單例模式


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;
}
}
}

最優,但是枚舉這個東西可讀性不高

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM