?第一章 一般技術
1.java只有唯一一種參數傳遞方式:by value(值傳遞)。對于primitive types(基本型別)很容易理解,對于object references(對象引用),傳遞的是object reference的拷貝。
2.polymorphism(多態)優于instanceof:instanceof很容易被誤用,很多場合都應該以多態代替,無論何時看到instanceof,請判斷是否可以改進以消除它。
3.避免創建重復對象。比如一個類A的某個方法新建了一個類B,且此類B不會改變,則每次建立該類A的一個對象就會新建B的對象,此時應把
B設為private static final。
4.清除過期的對象引用。
5.避免使用終結函數。因為終結函數可能得不到執行或很久后得到執行,所以要避免使用。顯示的中止方法通常與try-finally結構結合使用,防止出現異常時終結函數得不到執行。
eg: Foo foo = new Foo(...);
??? try{
??????? //do what must be done with foo???
??? }finally{
??????? foo.terminate();
??? }
6.通過私有構造函數來強化不可實例化的能力。比如一些工具類不希望被實例化,然而在缺少顯示構造函數時編譯器會自動提供一個默認構造函數,為防止以上情況要構造一個顯示的私有的構造函數。
eg:public class UtilityClass{
???? private UtilityClass(){
???? }
?? }
7.通過私有構造函數強化singleton屬性。singleton是指這樣的類,它只能實例化一次。singleton通常被用來代表那些本質上具有唯一性的系統組件,比如視頻顯示或者文件系統。
? eg:public class Elvis{
?????? public static final Elvis INSTANCE = new Elvis();
?????? private Elvis(){
?????? }
???? }
8.考慮用靜態工廠方法代替構造函數,但如果沒有其他強烈的因素,最好還是簡單的使用構造函數,畢竟它是語言規范。靜態工廠方法實際上是一個簡單的靜態方法,他返回的是類的一個實例。
? 有點:a.與構造函數不同,靜態工廠方法具有名字。
??????? b.與構造函數不同,它們每次被調用的時候不要求非得創建一個對象。
??????? c.與構造函數不同,與構造函數不同,它們可以返回一個原類型的子類型對象。
第二章 所有對象都通用的方法(equals(),hashCode(),toString(),clone(),Comparable接口)
一.按規則使用equals():
1.使用equals的規則:
? a.如果一個class的兩個對象占據不同的內存空間也可被視為邏輯相等的話,那么得為這個class提供一個equals()
? b.檢查是否等于this
? c.比較關鍵域以判斷兩個對象是否相等
? d.如果有java.lang.Object以外的任何base class實現了equals(),那么就應該調用super.equals()
? e.如果只允許同一個class所產生的對象被視為相等,則通常使用getClass()
??? eg1:一般情況
??? public boolean equals(Object obj){
??????? if(this == obj){
????????? return true;
??????? }
??????? if(obj != nul && getClass() == obj.getClass()){
????????? Test test = (Test)obj;
????????? if(***){//相等條件
????????????? return true;
????????? }
??????? }
??????? return false;
????? }
??? eg2:調用super.equals()情況
??? public boolean equals(Object obj){
????? if(super.equals(obj)){//已經包含了this == obj; obj !=null && getClass() == obj.getClass()的判斷
??????? Test test = (Test)obj;
????????? if(***){//相等條件
????????????? return true;
????????? }
??????? }
??????? return false;
????? }
? f.只有在不得不對derived class對象與base classes對象進行比較的場合中,才使用instanceof,并且你應該明白這樣做帶來的可能問題和復雜性,并且derived class和base classes都用instanceof實現equals()時,這種比較不會展現“對稱相等性”。
??? Base b;Derived d;//分別表示父類、子類
??? 1)父類實現equals,子類繼承父類的equals,b.equals(d) == d.equals(d);
??? 2)父類子類分別實現了equals,b.equals(d) != d.equals(b);
??? 3)父類未實現equals,子類實現了equals,b.equals(d) != d.equals(b);
2.對于既不是float也不是double類型的primitive types,使用==操作符;對于對象引用域,可以遞歸的調用equals方法;對于float域,先使用Float.floatToIntBits轉換成int類型值,然后使用==操作符比較int類型的值;對于double域,先使用Double.doubleToLongBits轉換成int類型的值,然后使用==操作符比較long類型的值.(這是由于存在Float.NaN、-0.0f以及類似的double類型的常量)
二.hashCode():
1。改寫equals時總是要改寫hashCode方法,如果不這樣作,會導致該類無法與所有基于散列值(hash)的集合類在一起正常工作,這樣的集合類包括HashMap、HashSet、HashTable
2。hashCode方法的簡單方法:
? 1。把某個非零數值(比如17),保存在int result變量里。
? 2。對于對象中每一個關鍵域f(指equals方法中考慮的每一個域),完成以下步驟:
? a)為該域計算int類型的散列碼c:
??? i.該域為boolean型,c = f ? 0 : 1
??? ii.byte, char, short, int型, c = (int)f
??? iii.long型, c = (int)(f ^ (f >>> 32))
??? iv.float型, c = Float.floatToIntBits(f)
??? v.double型, Double.doubleToLongBits(f)得到long型,然后按iii計算散列值
??? vi.如果是對象引用,c = (this.*** == null) ? 0 : this.***.hashCode();
??? vii.如果該域是個數組,則把其中每一個元素當作單獨的域來處理
?? b)result = 37 * result + c;//把每個c都組合到result中
?? 3。返回result
?? eg1:
?public int hashCode() {
???? int result = 17;
???? //對于關鍵域是id的情況
???? int idValue = (this.getId() == null) ? 0 : this.getId().hashCode();
???? result = (result * 37) + idValue;
???? //如果還有第二個關鍵域name
???? //int nameValue = (this.getName() == null) ? 0 : this.getName().hashCode();
???? //result = (result * 37) + nameValue;
???? this.hashValue = result;
?return this.hashValue;
?}
??? eg2:
?如果一個類是非可變的,并且計算散列碼代價較大,則應把散列碼存到對象內部:
?private int hashValue = 17;//先定義hashValue,不需要get/set方法
?........................
?public int hashCode() {//對于關鍵域是id的情況
???? if (this.hashValue == 17) {
??int result = 17;
??int idValue = (this.getId() == null) ? 0 : this.getId().hashCode();
??result = (result * 37) + idValue;
??//如果還有第二個關鍵域name
??//int nameValue = (this.getName() == null) ? 0 : this.getName().hashCode();
??//result = (result * 37) + nameValue;
??this.hashValue = result;
???? }
???? return this.hashValue;
?}
三。toString():會使這個類用起來更加方便。
四。謹慎的改寫clone()。實現拷貝的方法有兩個:一是實現cloneable接口(effective java 39頁,沒仔細看),二是提供拷貝構造函數
? public Yum(Yum yum);
? 或是上面的微小變形:提供一個靜態工廠來代替構造函數:
? public static Yum newInstance(Yum yum);
五、用到搜索、排序、計算極值的情況時,考慮實現Comparable接口。
public int compareTo(Object o)//方法不需要手工檢查參數的類型,如參數類型不符合會拋出ClassCastException;如參數為null,該方法拋出NullPointerException。
第三章 類和接口
1。使類和成員(變量、方法、內部類、內部接口)的可訪問能力最小化。
2。private和friendly成員都是一個類實現中的一部分,并不會影響到導出API。然而,如果這些域所在的類實現了Serializable接口,那么這些成員可能會被泄漏到導出API中。
3。如果一個方法改寫了超類中的一個方法,那么子類中該方法的訪問級別不能低于父類中該方法的訪問級別。特別是:類實現了接口,那么接口中的方法在這個類中必須聲明為公有的,因為接口中方法默認為public abstract。
六、異常處理
1.決不可忽略異常,即catch后什么也不做。
2.決不可掩蓋異常
try{
? e1;//異常1
? e2;//異常2
}catch(Exception e){
? e.printStackTrace()
}//只能捕獲異常2
辦法:要仔細分析,用棧來保存異常
3.覆寫異常處理時:
父類不拋出異常時,自類不能拋出異常。
父類拋出異常時,自類三種情況:a)不拋出異常b)拋出父類異常c)拋出父類異常的派生異常。
4.只要有finally塊就一定會進入,即使try-catch塊有return/break/continue語句。
5.養成將try/catch塊放在循環外的習慣,在不啟動JIT時節省時間。
posted on 2006-11-07 11:29
保爾任 閱讀(132)
評論(0) 編輯 收藏