首先看看我們有哪些視頻資源(免費獲取全套):
接著上期繼續看本書高質量編碼建議5、6條的閱讀筆記
第5條:避免創建不必要的對象
此條目下書中提到“當你應該重用現有對象的時候,請不要創建新的對象”。
最為突出的例子莫過於字符串常量的創建,眾所周知String字符串有兩種創建方式。
String str=“hello";
String str = new String("hello");
第一種String字符串的創建是在方法區(JDK7後改到了堆內存)中的常量池中創建一個”hello”常量,將來若再有一個字符串變量為“hello”時將直接指向常量池中的“hello”變量而不用重新創建;第二種則是會在堆變量中創建一個新的String實例,將來若再以此方式創建一個字符串變量為“hello”時還是會重新創建一個String實例。顯然第二種方式創建了一個“不必要”的實例,相比較而言第一種方式更加高效。
另外一個例子則是將”true”變量轉換為Boolean類型也有以下兩種轉換方式:
Boolean boolean = new Boolean("true");
Boolean boolean = Bolean.ValueOf("true");
第一種轉換方式也是每次都會在堆內存中創建一個新的Boolean實例;第二種查看其源代碼便知不會每次返回一個新的實例,返回的是一個在編譯器就已經確定了的static final Boolean型變量:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(String s) {
return toBoolean(s) ? TRUE : FALSE;
}
private static boolean toBoolean(String name) {
return ((name != null) && name.equalsIgnoreCase("true"));
}
書中舉了一個例子是否是在1946年至1964年出生來說明,這個例子在現實當中也很常見:
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
/**
* “是否在1946-1965年出生”
* 這在現實中應該是比較常見的一種寫法
* Created by yulinfeng on 8/5/17.
*/
public class Person {
private final Date birthDate;
public Person(Date birthDate) {
this.birthDate = birthDate;
}
public boolean isBabyBoomer() {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); //新創建Calendar實例
gmtCal.set(1949, Calendar.JANUARY, 1, 0, 0, 0);
Date boomStart = gmtCal.getTime(); //新創建Date實例
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.getTime(); //新創建Date實例
return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
}
}
這樣的代碼我相信人人都寫過類似的,書中提到這種代碼的寫法每次都創建新的實例對象,而實際上是不必要的,而給出了一種比較高效的代碼示例:
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
/**
* “是否在1946-1965年出生”
* 這在現實中應該是比較常見的一種寫法
* Created by yulinfeng on 8/5/17.
*/
public class Person {
private final Date birthDate;
private static final Date BOOM_START;
private static final Date BOOM_END;
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); //新創建Calendar實例
gmtCal.set(1949, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime(); //新創建Date實例
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime(); //新創建Date實例
}
public Person(Date birthDate) {
this.birthDate = birthDate;
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;
}
}
利用靜態代碼塊在類Person初始化的時候創建對象,而在之後調用方法判斷時不再每次重新創建新的實例對象,這種寫法有點“燒腦”,確實有點“不符合”編碼習慣,大概是因為這是需要思考才能寫出來的原因吧。
第6條:消除過期的引用對象
此條目較為容易理解,之所以要消除過期的對象引用其目的就在於儘量避免內存洩露的問題,書中舉了一個“棧”的例子,其中在彈出一個元素時代碼如下:
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
return elements[--size];
}
可以看到彈出元素時僅僅是將元素彈出後在將數組的索引-1,實際上數組維護的那個元素引用還在,也就是說那個被彈出的元素並不會被GC,如此一來最後就很有可能導致內存洩露的問題。解決此類的辦法就是,當不再使用這個元素時,將其置為null。
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null;
return result;
}
實際上當你寫出上面的代碼時一定注意這並不是在任意條件下都成立,你應該仔細思考此時的引用是否為過期引用,“清空對象引用應該是一種例外,而不是一種規範行為”。
看看我們的資料:
獲取方式:看文章尾部
想學習java,瞭解java,獲取java資源的歡迎進群:
java資源分享總群:238600498 ;java招聘信息共享群:489895481 ; Java高級架構師群:614527642
免費視頻資料獲取途徑:公眾平臺“java版web項目”(java_project)
閱讀更多 JavaLeader 的文章