effective java 讀書筆記

第二章:創建和銷毀對象

第7條:避免使用終結方法

final、finally、finalize的區別:

final:修飾符,關鍵字,可以修飾成員、方法和類,如果類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。將變量或者方法聲明為final,可以保證他們在使用中不被改變。
finally:一般是用于異常處理中,提供finally塊來執行任何的清楚操作,try{} catch(){} finally{}。
finalize:用于垃圾回收,在java中,允許使用finalize()方法在垃圾收集器將對象從內存中清理出去之前做必要的清理工作。

第三章對所有對象都通用的方法

第8條:覆蓋equals時請遵守通用約定

  1. 使用==操作符檢查“參數是否為這個對象的引用”。
  2. 使用instanceof操作符檢查“參數是否為正確的類型”。
  3. 把參數轉換成正確的類型。
  4. 對于該類中的每個“關鍵”域,檢查參數中的域是否與該對象中對應域相匹配。
  5. 當覆蓋玩equals方法之后,應該問自己三個問題:它是否對稱的、傳遞的、一致的?

warning:

  1. 覆蓋equals時總要覆蓋hashCode;
  2. 不要企圖讓equals方法過于智能;
  3. 不要將equals聲明中的Object對象替換為其他的類型;
public boolean equals(Myclass myclass){
  .....
}

第9條:覆蓋equals時總要覆蓋hashCode

每個覆蓋了equals方法的類中,也必須改服hashCode方法;
相等的對象必須具有相等的散列碼;
為不相等的對象產生不相等的散列碼;
不要試圖從散列碼計算中排除一個對象的關鍵部分來提高性能;

第10條:始終要覆蓋toString()

java.lang.Object提供了一個toString()方法,其結果為類名+@+hashCode十六位無符號表示方法。覆蓋toString()方法,獲取簡潔的類toString()結果,便于程序中類輸入結果的閱讀。

@Override
public String toString() {    
       return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}

第11條:謹慎地覆蓋clone

如果你覆蓋了非final類中的clone方法,則應該返回一個通過調用super.clone而得到的對象;
clone方法就是另一個構造器,你必須確保不會傷害到原始的對象,并確保正確地創建克隆對象中的約束條件;

第12條:考慮實現Complarable接口

Object中并沒有聲明compareTo()方法,compartTo()是Comparable接口的唯一方法,繼承此接口的類,可以實現類內部排序;

public interface Comparable{
   public int compareTo(T o);
}

其返回結果為int型,當對象小于、等于、大于指定對象T時,返回結果分別為負整數、零和正整數;

第4章:類與接口

第13條:使類和成員的可訪問性最小化

盡可能地使每個類或者成員不被外界訪問;

可訪問性:

  1. 私有的private;
  2. 包級私有的package-private,聲明該成員包內部的任何類都可以訪問這個成員,不對成員做任何訪問級別限制,則默認為包級私有;
  3. 受保護的protected,類及其子類可訪問protected級別成員;
  4. 公開的public,在任何地方都可以訪問該成員;

第14條:在公有類中使用訪問方法而非公有域

公有類永遠不要暴露可變的域。雖然這還是有問題,但是讓公有類暴露不可變的域其危害比較小。

第15條:使可變性最小化

為了使類成為不可變,要遵循下面五條規則:

  1. 不要提供任何會修改對象狀態的方法;
  2. 保證類不會被擴展;
  3. 使所有的域都是final的;
  4. 使所有的域都成為私有的;
  5. 確保對于任何可變組件的互斥訪問;

第16條:復合優于繼承

只有子類真正是超類的一部分時,才可以使用繼承,即當子類只有包含超類的屬性時才能使用繼承;
繼承的功能非常強大,但是由于繼承違背了封裝原則,因此也存在諸多問題。可以用復合和轉發機制來代替繼承,尤其是當存在適當的接口實現包裝類時,包裝類比子類更加健壯,功能也更強大;

第17條:要么為繼承而設計,并提交文檔說明,要么就禁止繼承

第18條:接口優于抽象類

第19條:接口只用于定義類型

接口只應用于定義類型,而不應該被用來到處常量;

第20條:類層次優于標簽類

標簽類過于冗長,容易出錯,并且效率低下;

第21條:用函數對象表示策略

第22條:優先考慮使用靜態成員類

嵌套類:是指被定義在另一個類的內部的類;
嵌套類分類:靜態成員類、非靜態成員類、匿名類、局部類;

第6章 枚舉和接口

第30條:用enum代替int常量

枚舉類型:是指由一組固定的常量組合成合法值得類型,例如一年的春夏秋冬四個季節;

為了將數據與枚舉常量關聯起來,得聲明實例域,并編寫一個帶有數據并將數據保存在域中的構造器。

第31條:用實例域代替序數

永遠不要根據枚舉的序數導出與它關聯的值,而是將它保存在一個實例域中。

第32條:用EnumSet代替位域

用OR位運算將幾個常量合并到一個集合中,稱作位域
EnumSet類可以有效地從單個枚舉類型中提取多個枚舉值;
eg:

public enum Style{
  BOLD,
  ITALIC,
  UNDERLINE
}
Set<Style> styleSet = EnumSet.of(Style.BOLD,Style.ITALIC);

由于枚舉類型要用在集合set中,所以沒有理由用位域表示它。

第33條:用EnumMap代替序數索引

EnumMap繼承AbstractMap實現Map接口,其實現Map所有操作的同時,具有獲取鍵列表和值列表功能;
getKeyUniverse()返回鍵列表,values()返回值列表;

第34條:用接口模擬可伸縮的枚舉

雖然無法編寫可擴展的枚舉類型,卻可以通過編寫接口以及實現該接口的基礎枚舉類型,對它進行模擬;

第35條:注解優先于命名模式

一般使用命名模式,表明有些程序需要通過某種工具或者框架進行特殊處理;
java 元注解:
1.@Target,    
2.@Retention,    
3.@Documented,    
4.@Inherited
有了注解,就不需要再使用命名模式了;

第36條:堅持使用override注解

使用@Override注解,表示該方法覆蓋超類中的方法;此注解保留源碼級別,當java文件被編譯后,@Override會被去除;使用此注解便于程序員對程序的理解,此外編譯器會根據此注解對無意識的覆蓋給予提示;

第37條:用標記接口定義類型

標記接口:是沒有包含方法聲明的接口,例如:Serializable就是一個標記接口,通過實現此接口,表明類可以被序列化。

第7章 方法

第38條:檢查參數的有效性

對參數的任何限制都是件好事。再設計方法時,應該使它們盡可能的通用,并符合實際需要。
每當編寫方式或者構造器的時候,應該考慮它的參數有哪些限制。應該把這些限制寫在文檔中,并且在這個方法體的開頭處,通過顯式的檢查來實施這些限制。

第39條:必要時進行保護性拷貝

  1. 類的客戶端會盡其所能來破壞這個類的約束條件,因此你必須保護性地設計程序。
  2. 保護性拷貝是在檢查參數的有效性之前進行的,并且有效性檢查是針對拷貝之后的對象,而不是針對原始對象。
  3. 對于參數類型可以被不可信任方子類話的參數,請不要使用clone方法進行保護性拷貝。
    保護性拷貝示例
public Date start(){
     return new Date(start.getTime());
}

第40條:謹慎設計方法簽名

  1. 謹慎的選擇方法名稱,應該始終遵循標準的命名習慣;
  2. 不要過于追求提供便利的方法;
  3. 避免過長的參數列表,可以通過輔助類縮短參數列表;

第41條:慎用重載

永遠不要導出兩個具有相同參數目的的重載方法

第42條:慎用可變參數

在定義參數數目不定的方法時,可變參數方法時不種很方便的方法,但是它們不應該過度濫用。如果使用不當,會產生混亂的結果。

第43條:返回零長度或者集合,而不是null

返回類型為數組或集合的方法沒理由返回null,應該返回零長度的數組或集合;

第44條:為所有導出的API元素編寫文檔注釋

第八章 通過程序設計

第45條:將局部變量作用域最小化

將局部變量最小化,可以增強代碼的可讀性和可維護性,并降低錯的可能性。

  • 要使局部變量的作用域最小化,最有力的方法就是在第一次使用它的時候聲明;

第46條:for-each循環優先于傳統的for循環

java1.5發行版本中引入for-each循環,通過完全隱藏迭代器或者索引變量,便面了混亂和出錯的可能。eg:

for(Element e : elements){
    doSomeThing(e);
}

有三種情況無法使用for-each循環:

  1. 過濾--如果需要遍歷集合或者數組,并刪除指定的元素;
  2. 轉換--如果需要遍歷列表或者數組,并取代它不分或者全部的元素值;
  3. 平行迭代--如果需要并行地遍歷多個集合,就需要顯式地控制迭代器或者索引變量,以便所有迭代器或者索引量都可以得到同步前移;

第47條:了解和使用類庫

java.io java.lang java.util java.util.concurrent類庫是每個程序員都應該學習的;
多了解類庫,多閱讀類庫實現原理及實現方式,類庫的代碼比你自己編寫的代碼更好一些,并隨著時間推移而不斷改進。

第48條:如果需要精確的答案,避免私用floate和double

使用BigDecimal代替floate和double

第49條:基本類型有限裝箱基本類型

基本類型與基本裝箱類型的區別:

  1. 基本類型只有值,裝箱基本類型則具有它們的值不同的同一性;
  2. 基本類型只有功能完備的值,而每個裝箱基本類型除了它對基本類型的所有功能值之外,還有個非功能值:null
  3. 基本類型比裝箱基本類型更節約時間和空間

第50條:如果其他類型更合適,避免使用字符串

字符串不適合代替其他值類型
字符串不適合代替枚舉類型
字符串不適合代替能力表
如果可以使用更加合適的數據類型,或者可以編寫更加適當的數據類型,就應該避免使用字符串

第51條:當心字符串連接的性能

為了獲取能夠接受的性能,請使用StringBuilder代替String

第52條:通過接口引用對象

如果有合適的接口類型存在,那么對于參數、返回值、變量和域來說,就都應該使用接口類型進行聲明;

第53條:接口優先于反射機制

核心反射機制:提供了“通過程序來訪問關于已裝載的類的信息”的能力;

第54條:謹慎地使用本地方法

本地方法是指用本地程序設計語言(c或者c++)來編寫的特殊方法;
本地方法時不安全的,使用本地方法的應用程序不再能免受內存毀壞錯誤的影響。因為本地語言是平臺相關的,使用本地方法的語言不再是可移植的。

第55條:謹慎地優化

要努力編寫好的程序而不是快的程序
每次試圖優化之前和之后,要對性能進行測量

第56條:要遵循普遍的命名規范

跟著項目走,寫代碼時重視命名規范


....未完待續

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容