Effective Java理解(一)
阿新 • • 發佈:2019-12-31
靜態工廠方法替換建構函式 - 何時替換
- 靜態工廠方法含有名字,它能提供更加明確的資訊
- 當建立物件的代價很大時,需要使用享元模式時
- 能返回其返回型別的任何子型別的物件(? extends T),比如java .util. collections
- 返回物件的類可以根據輸入引數的不同而不同。
- 服務提供者框架中編寫包含方法的類時,返回的物件的類不需要存在(這句話,單獨拿在這兒來說,我是懵逼的),在書中用JDBC來說明瞭一下,但解釋得十分籠統,這裡重新釋義一下
服務提供者框架
。-
Class.forName("com.mysql.jdbc.Driver");
這樣一個語句會例項化一個Driver類(提供服務者實現類),並將這個類的例項註冊到DriverManager(服務提供者註冊類)。 -
DriverManager.getConnection("jdbc:mysql://...","...","...");
這裡通過建立連線的URL等資訊來獲取資料庫連線。DriverManager通過傳進來的url資訊判斷出你是要獲取那個服務提供者提供的服務。因為1
中已經將提供服務者實現類註冊到DriverManager了,DriverManager獲取到這個服務提供者實現類物件之後,通過呼叫它的getService(mysql裡面是connect方法)方法獲取到服務具體實現類物件,返回的卻是java.sql.Connection介面物件(因為服務具體實現類實現了Connection介面),這樣把服務具體實現類物件隱藏了。提供了很好的擴充套件性。 - 在Java1.6的時候加入了java.util.ServiceLoader,可以通過這個類來實現服務提供者。
-
靜態工廠方法的常用名稱:
-
from
—— A 型別轉換方法,它接受單個引數並返回此型別的相應例項,例如:Date d = Date.from(instant); -
of
—— 一個聚合方法,接受多個引數並返回該型別的例項,並把他們合併在一起,例如:Set faceCards = EnumSet.of(JACK,QUEEN,KING); -
valueOf
—— from 和 to 更為詳細的替代 方式,例如:BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE); -
instance
或getinstance
—— 返回一個由其引數 (如果有的話) 描述的例項,但不能說它具有相同的值,例如:StackWalker luke = StackWalker.getInstance(options); -
create
或newInstance
—— 與 instance 或 getInstance 類似,除了該方法保證每個呼叫返回一個新的例項,例如:Object newArray = Array.newInstance(classObject,arrayLen); -
getType
—— 與 getInstance 類似,但是如果在工廠方法中不同的類中使用。Type 是工廠方法返回的物件型別,例如:FileStore fs = Files.getFileStore(path); -
newType
—— 與 newInstance 類似,但是如果在工廠方法中不同的類中使用。Type 是工廠方法返回的物件型別,例如:BufferedReader br = Files.newBufferedReader(path); -
type
—— getType 和 newType 簡潔的替代方式,例如:List litany = Collections.list(legacyLitany);
- tips: 當建構函式的引數過多使用Builder
依賴注入替換硬連線資源的方式
如果一個類依賴於一個或多個底層資源,這些資源的行為會影響類的行為的時候,不要使用單例或靜態的實用類來實現這個類,並且不讓類直接建立這些資源。相反,將資源或工廠傳遞給構造方法(或靜態工廠或 builder 模式)。這種稱為依賴注入的實踐將極大地增強類的靈活性、可重用性和可測試性。
重寫equals方法
- 自反性: 對於任何非空引用 x,x.equals(x) 必須返回 true。
- 對稱性: 對於任何非空引用 x 和 y,如果且僅當 y.equals(x) 返回 true 時 x.equals(y) 必須返回 true。
- 傳遞性: 對於任何非空引用 x、y、z,如果 x.equals(y) 返回 true,y.equals(z) 返回 true,則 x.equals(z) 必須返回 true。
- 一致性對於任何非空引用 x 和 y,如果在 equals 比較中使用的資訊沒有修改,則 x.equals(y) 的多次呼叫必須始終返回 true 或始終返回 false。
- 對於任何非空引用 x,x.equals(null) 必須返回 false。
- 當重寫 equals 方法時,同時也要重寫 hashCode 方法。
- 不要讓 equals 方法試圖太聰明。如果只是簡單地測試用於相等的屬性。
- 在 equal 時方法宣告中,不要將引數 Object 替換成其他型別。
//正確示範
@Override
public boolean equals(Object o) {
if (!(o instanceof MyType))
return false;
MyType mt = (MyType) o;
...
}
複製程式碼
實現Comparable介面
- 使用Arrays.sort來完成排序
- 無論何時實現具有合理排序的值類,都應該讓該類實現 Comparable 介面。 比較 compareTo 方法的實現中的欄位值時,請避免使用
<
和>
運運算元。 相反,使用包裝類中的靜態 compare 方法或 Comparator 介面中的構建方法。
// BROKEN difference-based comparator - violates transitivity!
static Comparator<Object> hashCodeOrder = new Comparator<>() {
public int compare(Object o1,Object o2) {
return o1.hashCode() - o2.hashCode();
}
};
/**
*不要使用這種技術!它可能會導致整數最大長度溢位和 IEEE 754 浮點運算失真的危險[JLS 15.20.1,15.21.1]。 此外,由此
*產生的方法不可能比使用上述技術編寫的方法快得多。 使用靜態 compare 方法:
*/
// Comparator based on static compare method
static Comparator<Object> hashCodeOrder = new Comparator<>() {
public int compare(Object o1,Object o2) {
return Integer.compare(o1.hashCode(),o2.hashCode());
}
};
  
//或者使用 Comparator 的構建方法:
// Comparator based on Comparator construction method
static Comparator<Object> hashCodeOrder =
Comparator.comparingInt(o -> o.hashCode());
//java8 比較 正序
someList.sort((Message m1,Message m2) -> m1.getSendDate().compareTo(m2.getSendDate()));
複製程式碼
參考:
-
《effective java》3rd
-- Joshua Bloch - JAVA 服務提供者框架介紹