Think in java讀書筆記

第一章:對象簡介
1、Java的五大特徵,也是面向對象的五大特徵:
   Everything is an object:萬物皆對象
   A program is a bunch of objects telling each other what to do by sending messages:程序就是一組相互之間傳遞信息,告訴對方該幹些什麼的對象
   Each object has its own memory made up of other objects:每個對象都利用別的對象來組建它自己的記憶
   Every object has a type:對象都有類型
   All objects of a particular type can receive the same messages:所有屬於同一類型的對象能接收同樣的信息

2、作者在第一章講的是一些OOP概念上的東西,在我看來也有許多哲學上的東西,多看幾遍或許會頓悟。

 

 

第二章:萬物皆對象

1、在Java中,我們直接操控的不是類本身,而是類的一個實例,或者說是Reference。Java沒有地址傳遞之說。
   (chap2,P2)

2、Java把對象,也就是類存放在“堆”裏,而把其他數據和對象的reference存放在“棧”裏,對操作來收,棧比堆要快。
   (chap2,P3)

3、因爲棧比堆要快,所以作爲特例,Java的primitive類型的變量也存放在棧裏,這樣可以提高效率,另外一方面來說,primitive類型的數據不是類,所以,它們也沒有reference。
   (chap2,P4)

4、Java不允許在同一個方法中定義同樣名稱的變量,如:
   {
 int x = 12;
 {
  int x = 16;
 }
   }
   這在C++中是允許的,在Java中卻會出現編譯錯誤。
   (chap2,P7)

5、無需關心清理不再被使用的reference,Java的Gabage Collector會幫你做這一切的。
   (chap2,P8)

6、對於primitive類型的變量,如果這個變量是類的成員,則類會對其進行初始化,如果不是類的成員,則不會對其初始化,它可能是一個任意的值。
   (chap2,P9)

7、javadoc非常強大,但要求我們寫程序的時候要有豐富的註釋和良好的習慣。

 

 

第三章:流程控制

1、幾乎所有的運算符都只能作用於primitive。但“=”、“==”、“!=”是例外,它們可以運用於所有對象,此外,String類也支持“+”和“+=”。
   (chap3,P2)

2、Reference變量的賦值,會使表達式左邊的reference丟失原來的對象,原來的對象成了沒有reference的內存垃圾。
   (chap3,P3)

3、Java的書籍總是強調Java沒有地址傳遞,但我覺得reference傳遞就是地址傳遞。

4、Integer n1 = new Integer(47);
   Integer n2 = new Integer(47);
   System.out.println(n1.equals(n2));
   打印的結果是true,不要認爲理所當然就是這樣,其實,equals比較的是reference,這裏是兩個reference,顯然不會相等,之所以輸出true,是因爲Integer類中已經對equals函數
   做了處理,如果是自己寫的類,而沒有重載equals,那麼打印的肯定是false。
   (chap3,P11)

5、Java提供了位操作符,但我覺得沒有必要使用它。
   (chap3,P15)

6、在Java中,逗號運算符只能用在for循環中。
   (chap3,P37)

7、switch只能用char、byte、short、int。
   (chap3,P43)

 


第四章:初始化與清理
1、primitive類型的重載慎用。
   (chap4、P7)

2、返回值不能重載,因爲存在雖然方法有返回值,但程序中並不關注返回值的情況,如:
   定義:int f(){}; String f(){};
   調用 f(),此時虛擬機就不知道該調用哪個f了。
   (chap4、P11)

3、類中的普通方法不能調用構造函數,構造函數能相互調用,但只能用this關鍵字。
   (chap4、P13)

4、一般來說,類中無需使用finalize(),因爲虛擬機會自動進行垃圾清理,但有種特殊情況,聲明瞭一個對象,但並沒有refrence,比如:
   class Aclass(){....};
   ...
   new Aclass();
   因爲沒有refrence,那麼虛擬機會認爲它已經沒有用了,就可以回收了,但此時如果你不希望它回收,那麼可以在finalize函數中實現,具體可參考書本的例子。
   (chap4、P16)

5、內部變量在使用之前必須初始化;所謂“使用”是指出現在表達式右邊、方法的參數等,而不是表達式的左邊,例如:
   String s = "i love java";
   int i;
   i = s.length();
   是正確的;而
   int i;
   i++;
   是錯誤的。因爲i++相對於i = i + 1
   但是,如果不是內部變量而是類的的成員數據,則不需要初始化,因爲編譯器不知道會在哪個方法中被初始化。對於primitive的成員數據,Java會自動賦予初始值,如:
   boolean = false
   char  = (char)0  ----空格
   byte  = 0
   int  = 0
   long  = 0
   float = 0
   double = 0
   對於對象的成員數據,沒有初始化之前等於null,所以,primitive的成員數據沒有初始化之前被使用並不會發生錯誤,但對象數據在運行時就會發生exception。
   有一種特殊情況,如:
   int [] a = new int[4];
   此時,看上去只初始化了數組的大小而沒有初始化數組的成員,但在java中,這也是沒有問題的,java給每個數組成員自動進行了初始化。
   (chap4,P22)

6、類實例化的時候總是先執行成員數據的定義(如果在定義的時候進行初始化的話此時就初始化了),然後再執行構造函數,而不管在代碼順序上成員數據在前還是構造函數在前。
   (chap4,P26)

7、對於static類型的成員變量,static類型的成員變量總是比其他成員變量先初始化,static類型的成員變量只初始化一次,只有被用到的static成員變量纔會被初始化。
   此處,“被用到”在我來理解,是從main函數開始檢查的,如果main函數中定義了靜態變量或者被main函數調用的其他類中定義了靜態變量,這些靜態變量就“被用到”了。
   (chap4,P27)

8、primitive類型的數組可以用new來初始化,如int[] a = new int[]{1,2,3,4},也可以直接用形如int[] a = {1,2,3,4}的方式來初始化,但如果不是primitive的變量就只能用new來初始化。
   (chap4,P34)

9、數組初始化的時候,int[] a = {1,2,3,4,}; 4後面有逗號,對不對?答:對,最後的逗號有與沒有都可以。
   (chap4,P35)

 

 

第五章:隱藏實現

1、並非每一個java文件都需要一個public類,但一個java文件只能有一個public類。如果沒有public類,那麼文件名可以隨便取。
   (chap5,P4)

2、使用import的時候,引用的類庫要麼能在CLASSPAHT中找到,要麼在當前路徑在加上import的相對路徑中能找到,如:import com.kingworld.util,如果當前路徑是D:/JavaWork,
   那麼這些被import的類庫可以在D:/JavaWork/com/kingworld/util目錄下。
   (chap5,P7)

3、關於Java的package,如果打包成jar文件,必須把這個文件放到CLASSPATH能找到的路徑中去。
   (chap5,P7)

4、Java的訪問符包括,public、protected、private和沒有訪問符(package),此處的訪問符是指類的成員的訪問符。其訪問權限分別是:public>package>protected>private。
   package的訪問權限不僅僅是使同一個package中其他類能訪問這個類的public、protected、package成員,也能訪問private成員。
   (chap5,P10)

5、相對於成員的訪問權限,類沒有private的訪問權限,因爲private的類沒有任何價值;同時也沒有protected的訪問權限。

 

第六章:複用類

1、toString是一個特殊的方法,當編譯器需要一個String而你的類是一個對象的時候,編譯器會自動調用toString方法,當然,你得保證你的類裏面有這個方法。
   (chap6,P2)

2、往每個類中都寫一個main函數,會使調試方便得多。
   (chap6,P6)

3、如果基類中沒有默認的(即沒有參數的)構造函數而有有參數的構造函數,則在子類的構造函數中必須調用基類的構造函數,否則編譯會出錯。也就是說,當子類實例化的時候
   虛擬機自動去調用基類的默認的構造函數,除非在子類的構造函數中顯式地調用了基類的非默認的構造函數。
   (chap6,P9)

4、編譯器會強制將你基類的構造函數的調用放在派生類的構造函數的最前面。也就是說,在它之前不能有任何東西。
   (chap6,P9)

5、雖然編譯器會強制你對基類進行初始化,並且會要求你在構造函數的開始部分完成初始化,但它不會檢查你是不是進行了成員對象的初始化。
   (chap6,P11)

6、合成還是繼承?一般來說,合成用於新類要使用舊類的功能,而不是其接口的場合。也就是說,把對象嵌進去,用它實現新類的功能,但是用戶看到的是新累的接口,而不是嵌進去
   的對象的接口。
   (chap6,P16)

7、一般情況下,應該將類的成員數據定義成private。
   (chap6,P16)

8、上傳(upcasting)總是安全的。
   (chap6,P19)

9、private方法都隱含有final的意思。由於你不能訪問private的方法,因此你也不能複寫它。你可以給一個private方法加final修飾符,但這樣做什麼意義也沒有。
   (chap6,P24)

10、9中提到的不能複寫private函數,是指,該函數在基類中是private的,並且在派生類中也是private的。如果在派生類中不是private的,則可以複寫。
   (chap6,P24)

 


第七章:多態性

1、“封裝”通過將數據的特徵與行爲結合在一起,創建了一種新的數據類型。“隱藏實現”通過將細節設置成private,完成了接口與實現的分離。而多態性是站在“類”的角度來
    處理這種邏輯上的分離的。
   (chap7,P2)

2、“上傳”使得類的動態性得以實現,但需要注意的是,只有基類是public的情況下,擴展類的複寫纔可以實現,比如下面的例子:
   public class Test {
 private void f() {
  System.out.println("private f()");
 }

 public static void main(String[] args) {
  Test po = new Derived();
  po.f();
 }
   }

   class Derived extends Test {
 public void f() {
  System.out.println("public f()");
 }
   }
   例子中,Test.f是private的,所以Derived.f其實不是Test.f的複寫,Derived.f是一個全新的方法,它連重載都算不上,因爲Derived根本看不到基類的f()。
   所以,輸出的應該是private f(),而不是public f()。
   (chap7,P12)

3、如果類包含一個或多個抽象方法,那麼這個類必須定義爲abstract,但如果類沒有abstract方法,也可以將類定義爲abstract。
   (chap7,P13)

4、構造函數的調用順序:
   ①調用基類的構造函數。這是一個遞歸過程,因此會先創建繼承體系的根,然後是下一級派生類,依此類推,直到最後一個繼承類的構造函數
   ②成員對象按照其聲明的順序進行初始化
   ③執行繼承類的構造函數的正文。
   其實,還不如這樣表述表決方便:在一個類的初始化過程中,先按成員對象的聲明順序初始化這些成員變量,然後執行其構造函數;如果有基類,則先初始化基類。
   (chap7,P17)

5、如果要內存清理,則可以從基類開始寫一個函數,函數名可以自己定,但調用的時候,必須從頂層開始執行,這剛好與構造函數的調用順序相反。
   (chap7,P18)

6、開始做Java的時候,不要想着把整個程序做成一個類系,比較好的辦法是合成。
   (chap7,P23)

 

 

第八章:接口與內部類

1、接口中的方法是自動public的,即,如果你沒有對其進行設置,它不會象類一樣認爲它是package,而是認爲是public,另外,接口中的方法是不允許爲private和protected的。
   (chap8,P3)

2、在繼承和實現同時進行的時候,在聲明一個類的時候,應該先繼承後實現。
   (chap8,P6)

3、使用接口還是抽象類?如果沒有成員數據和方法的實現,則應該優先考慮使用接口。
   (chap8,P7)

4、接口中的成員變量自動就是public和final的,所以不必特別聲明,這樣可以實現與C語言的enum相似的功能。如:
   public interface Months {
    int JANUARY = 1, FEBRUARY = 2, MARCH = 3, APRIL = 4, MAY = 5, JUNE = 6, JULY = 7, AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10,NOVEMBER = 11, DECEMBER = 12;
   }
   (chap8,P10)

5、內部類是一種非常有價值的特性,它能讓你在邏輯上將相互從屬的類組織起來,並且在類的內部訪問控制權限。但是切記,內部類和合成是截然不同的。
   (chap8,P15)

6、內部類可以被創建在方法裏,甚至是任意一個作用域裏。
   (chap8,P18)

7、內部類能訪問宿主類的任何成員。
   (chap8,P24)

8、嵌套類就是static的內部類。
   (chap8,P26)

9、每個內部類都可以獨立地繼承某個“實現(implementation)。因此,內部類不會受“宿主類是否已經繼承了別的實現”的約束。
   (chap8,P34)

10、雖然作者說了很多內部類的好處,但我覺得我還是看不太懂,留待以後慢慢琢磨吧。

 

 


第九章:異常帶來處理錯誤

1、如果一個方法在聲明的時候拋出一個異常,比如public void f() throws SimpleException,那麼在調用的時候必須進行異常捕捉。
   (chap9,P6)

2、打印錯誤信息是時候,System.err比System.out好,因爲後者可能不重定向。
   (chap9,P6)

3、自己創建的異常類可以有帶參數的構造函數,也可以有其他的成員。
   (chap9,P6)

4、Throwable類的printStackTrace方法返回“被調用的方法是經過怎樣一個順序到達異常發生地點”的信息。
   (chap9,P7)

5、異常說明(即在方法後面跟上throws關鍵字和要拋出的異常的類名稱)可以讓程序員很明確的知道這個方法可能會拋出什麼樣的異常。
   (chap9,P9)

6、異常NullPointerReference虛擬機會自動拋出,不必處處調用。
   (chap9,P18)

7、無論是否拋出異常,finally塊總是會被執行。
   (chap9,P20)

8、異常運用原則:
   ①在合適的地方處理問題。(避免在自己還不知道該如何處理的情況下去捕捉異常)
   ②把問題解決掉,然後重新調用那個引起問題的方法
   ③修正一下問題,然後染過那個方法在繼續下去
   ④用一些別的,不準備讓這個方法返回的數字來進行計算
   ⑤把當前允許環境下能做的事情全部做完,然後把相同的異常拋到更高層
   ⑥把當前允許環境下能做的事情全部做完,然後把拋一個不同的異常到更高層
   ⑦中止程序
   ⑧簡化(如果異常結構把事情搞得太複雜了,那用起來會非常痛苦也很煩人)
   ⑨把類庫和程序做得更安全(這既是在爲調試作短期投資,也是在爲程序的健壯性作長期投資)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章