Thinking In Java 讀書筆記

Thinking In Java

目錄:html

 

 

第一章——簡介

Java編程思想 第四版 Bruce Eckel著 陳昊鵬譯java

源代碼資源位於 www.MindView.net程序員

第二章——一切皆對象

1. 標識符

  • 常見的String s語句只是建立了一個引用,並非對象。
  • 能夠把引用當作遙控器,對象當作電視機。遙控器保證與電視機的鏈接並控制電視機。可是咱們實際操做的是遙控器(引用),再由遙控器控制電視機。

2. 引用所指的對象必須由本人建立

  • 如經常使用的String s = 「abc」;就至關於String s = new String(「abc」);前半句建立引用,後半句建立對象,=將引用指向了對象。編程

    在Java中,一個引用能夠指向0個或者1個對象,一個對象能夠有0個或者1個或者多個引用。如在上面的代碼中加入s2=s;就至關於String對象」abc」增長了一個引用s2。數組

  • 熟悉了上面的說明,作下這個測試吧,s1~6的相等關係是(內存等,非值等)?緩存

    1. String s1 = "abc";
    2. String s2 = s1;
    3. String s3 = "abc";
    4. String s4 = new String("abc");
    5. String s5 = s4;
    6. String s6 = new String("abc");

    s1 = s2 = s3 != s4架構

    s4 = s5 != s6app

  • 計算機的數據存儲從快到慢分爲寄存器、堆棧、堆、常量存儲、非RAM存儲。引用位於堆棧中,而對象位於堆中。dom

3. 基本類型

  • Java中基本類型在不一樣架構的機器上佔用相同的存儲空間(Java良好的移植性)。
基本類型 大小 最小值 最大值 包裝器類型
boolean - - - Boolean
char 16 bits Unicode 0 Unicode 2^16 -1 Character
byte 8 bits -128 +127 Byte
short 16 bits -2^15 +2^15 -1 Short
int 32 bits -2^31 +2^31 -1 Integer
long 64 bits -2^63 +2^63 -1 Long
float 32 bits IEEE754 IEEE754 Float
double 64 bits IEEE754 IEEE754 Double
void -     Void
  • 轉換關係:eclipse

    byte也叫字節,簡稱B。1B = 8 bit。bit也叫比特,是一個二進制單位。1KB = 1024B。

  • 高精度的整型BigInteger和浮點型BigDecimal不屬於基本類型,詳情參考JDK。

4. Static

  • static 修飾的成員變量和函數,對該類和該類全部的實例都只有一份存儲空間(能夠說是類和類的實例共享的)。調用方法能夠是實例名.或者類名.

* Tips

  • 函數的返回類型若爲void,則return方法只是用來退出函數。
  • java.lang是默認導入到每個Java文件中的。

5. JavaDoc

  • Java解決了程序員同時須要維護文檔和代碼兩份無關聯文件的繁瑣。Java能夠將代碼中的註釋生成爲HTML格式。

    Java終端採用命令 javadoc xxx.java便可。對於中文doc採用utf-8編碼,即 javadoc xxx.java -encoding UTF-8 -charset UTF-8

  • Java中的註釋有兩種( /*java*/ 和 //java ),可是javadoc能夠導出的是下列方式的註釋:

    1. /** This is a annotation */
    1. /**
    2. * This is an annotation
    3. * @author Aran
    4. * @param args
    5. */
  • 註釋要有註釋的規範,java的註釋主要有類註釋、域註釋和方法註釋,分別出如今類、域(變量定義)和方法定義以前。此外還有一些約定俗成的標籤,如@param,@author等等,在此不作贅述。

  • eclipse也能夠對整個project導出doc,而且能夠本身編寫doclets自定義javadoc的導出規則。這些自行參考網上文獻,再次不作贅述。

* Tips

  • 組成類的全部單詞首字母大寫(不須要鏈接線),變量函數的首個單詞首字母小寫,其它大寫。

第三章——操做符

1. +號

  • +號除了傳統的加,+還意味着」字符串鏈接」,若是必要,它還要執行」字符串轉換」。當編譯器觀察到一個String後緊跟一個+後又緊跟一個非String類型的元素時,就會嘗試將這個非String類型的元素轉換爲String型。

2. =號

  • 賦值操做分類兩種類型。分別是對基本數據類型的賦值和對針對對象的賦值。前者直接將一個地方的內容複製到了另外一個地方;後者只是引用之間的複製,引用所指的依然是本來的對象。

* Tips

  • 一個java文件中能夠有多個類,可是隻能有一個和java文件同名的public類。其它類直接定義爲class 類名{}
  • java中生成random數據須使用java.util.Random類,併爲初始化函數提供種子。(不提供則採用當前時間做爲種子)對實例調用.nextInt/Float/Long/Double()獲取隨機數字。(注意int型的下限爲0)

3. ++和–

  • 對於前綴運算符會先執行運算,在生成值;對於後綴運算符會先生成值再執行運算。在這裏尤爲注意java 中的中間緩存變量機制帶來的一些bug,參考本Wiz中的《Java中的中間緩存變量機制》。

4. ==和equals

  • equals主要用來比較內容等,而==是比較對象的引用。相似於Python當中的==和is。

5. 邏輯操做符

  • 即 與&& 或|| 非! 和C和C++同樣java的邏輯運算中也會出現短路現象:在前部分的運算獲得表達式結果後再也不計算後面的表達式。可是和C和C++不同的是,
  • Java中的或與非操做只可應用於布爾值,不可用於Int型。並且Int型和布爾型也沒有任何的轉換關係,如if(0)的作法在Java中是錯誤的。 可是在該是用String型的時候是用了布爾型,布爾值會自動轉換成爲適當的文本類型。

6. 直接常量

  • java容許在基本類型的數值後面加上L(表示Long)、F(表示Float)、D(表示Double)來明確指定一個數的數據類型。如float i = 0.0F;

7. 指數表示

  • 採用底數e表明10來表示指數。如1.39*10^-43這樣的數採用1.39E-43F來表示。(後面的f見上文直接變量)

8. 按位操做符

  • 與& 或| 非~ 異或^
  • 操做對象都是單個比特,即二進制位。對於布爾值,不能執行非的操做。且不會短路操做。
  • 異或,就是相異爲真,相同爲假。

ps. 移位操做符在本書p49頁,使用較少,在此不作贅述。

9. 三元操做符

  • boolean-exp ? value0 : value1
  • 若是boolean-exp爲真,則輸出value0;爲假則輸出value1。

10.類型轉換

  • java中的類型轉換分爲兩種:

    1. 窄化轉換,即將能容納更多數據信息的類型轉換爲能容納較少數據信息的類型。
    2. 擴輾轉換,即將能容納較少數據信息的類型轉換爲能容納較多數據信息的類型。
  • 窄化轉換,通常而言須要顯時表示。從long型、float型、double型轉換爲int,從int型轉換爲char、short、byte都是窄化。須要 (新類型)value 來表示。

  • 擴輾轉換通常默認進行,爲了規範,建議顯時標註。

  • 窄化轉換的截尾和舍入:

    默認的窄化轉換,即從float轉int是直接執行截尾,把小數點後面數字直接去除。

    若是想要四捨五入,則須要使用java.lang.Math中的round()方法

  • 擴輾轉換的提高:

    一個計算式中同時出現好幾種類型,則會把計算結果提高爲最大類型。

第四章——控制執行流程

包含if-else、while、do-while、for、for each、return、break和switch語句。

1. for語句中的逗號操做符

  • 不一樣於逗號分隔符(經常使用於分割函數參數),這裏的逗號操做符for語句的控制表達式中的初始化和步進控制部分。

  • 如示例:

    1. for (int i = 1, j = i + 10; i < 5 && j < 30; i++, j = j * 2) {
    2. System.out.println("i = "+i+" j = "+j);
    3. }

2.For Each語句

ForEach語句是一種更加簡潔的for語句,經常使用於數組、容器和Iterable對象。

ForEach語法能夠沒必要建立int變量去對由訪問項構成的序列進行計數,ForEach將自動產生每一項。

語法的默認表達式爲:for(類型 x : 數組/容器){ x… }

  • 以給float數組賦值和顯示爲例:

    1. Random rand = new Random();
    2. float[] f = new float[10];
    3. for (float x : f)
    4. {
    5. x = rand.nextFloat();
    6. System.out.println(x);
    7. }
  • 以給String對象迭代顯示爲例:

    1. for(char x : "Happy Spring Festival".toCharArray())
    2. {
    3. System.out.print(x+".");
    4. }

    這裏使用了String類中的toCharArray()函數,把String類轉換成char數組。

3.無條件分支語句(Return、Break、Continue、Goto)

  • Return

    return會致使當前方法退出並返回那個值。若是一個方法聲明並不是返回void,那麼必須確保每一條代碼路徑都返回一個值。

  • Break和Continue

    前者強行退出循環,不執行循環中剩餘的語句。後者則只是中止執行當前的迭代,退回循環起始處並開始下一次迭代。

  • goto

    儘管java中保留了goto的功能,但並無goto關鍵字。採用break、continue+標籤的方法,能夠實現goto的功能。

    標籤是後面跟有冒號的標識符,相似:

    label1:

    先上結論:

    1. 通常的continue會退回最內層循環的開頭(頂部),並繼續執行。
    2. 帶有標籤的continue會到達標籤的位置,並從新進入緊接在那個標籤後面的循環。
    3. 通常的break會中斷並跳出當前循環。
    4. 帶有標籤的break會中斷並跳出標籤所指的循環。

    java 中的標籤後面必須緊跟循環語句,不然會被忽略掉從而在continue和break語句中沒法識別。

    經過代碼來加深理解(參考P71-72頁代碼):

    1. public static void main(String[] args) {
    2. int i = 0;
    3. outer:
    4. for (; true;) {
    5. System.out.println("Enter outer-for");
    6. inner:
    7. for (; i < 10; i++) {
    8. System.out.println("Enter inner-for");
    9. System.out.println("i = " + i);
    10. if (i == 1) {
    11. System.out.println("continue");
    12. continue;
    13. }
    14. if (i == 2) {
    15. System.out.println("break");
    16. i++;// 不然i沒法自增
    17. break;
    18. }
    19. if (i == 3) {
    20. System.out.println("continue inner");
    21. continue inner;
    22. }
    23. if(i == 4){
    24. System.out.println("break inner");
    25. i++;// 不然i沒法自增
    26. break inner;
    27. }
    28. if(i == 5){
    29. System.out.println("continue outer");
    30. i++;// 不然i沒法自增
    31. continue outer;
    32. }
    33. if(i == 6){
    34. System.out.println("break outer");
    35. break outer;//直接退出
    36. }
    37. }
    38. }
    39. }

    出現的結果是:

    1. Enter outer-for
    2. Enter inner-for
    3. i = 0
    4. Enter inner-for
    5. i = 1
    6. continue
    7. Enter inner-for
    8. i = 2
    9. break
    10. Enter outer-for
    11. Enter inner-for
    12. i = 3
    13. continue inner
    14. Enter inner-for
    15. i = 4
    16. break inner
    17. Enter outer-for
    18. Enter inner-for
    19. i = 5
    20. continue outer
    21. Enter outer-for
    22. Enter inner-for
    23. i = 6
    24. break outer
    25. xxxxxxxxxx1 1

    值得注意的是,break和continue outer的操做會致使內層循環不執行++,這個要理清楚。

4.Switch

標準的switch範式以下:

  1. switch(integral-selector){
  2. case integral-value1 : statement; break;
  3. case integral-value2 : statement; break;
  4. default: statement; break;
  5. }

使用switch語句須要注意一下幾點:

  1. 語句中integral-selector(整數選擇因子)是一個可以產生整數的表達式。switch會個將表達式的結果與每一個integral-value對比,若相符則執行對應語句。若沒有相符的,則執行default語句。
  2. 整數選擇因子必須是int或者char型的整數值。
  3. 進入相應的case後,若沒有break,則順序執行下面的語句。default也是這樣!

下面的例子(由P74-75,4.8改編)判斷a-z哪些是元音哪些是輔音:

  1. public static void main(String[] args) {
  2. for (int i = 0; i < 26; i++) {
  3. System.out.print((char)('a' + i) + ":");
  4. switch ('a' + i) {
  5. case 'a':
  6. case 'e':
  7. case 'i':
  8. case 'o':
  9. case 'u':
  10. System.out.println("vowel");
  11. break;
  12. case 'y':
  13. case 'w':
  14. System.out.println("sometimes vowel");
  15. break;
  16. default:
  17. System.out.println("consonant");
  18. }
  19. }
  20. }

利用了case下沒有break就依次順序執行的原理。

第五章 初始化與清理

1.構造器來確保初始化

  • Java中構造器採用和類相同的名字。

  • 構造器不會返回任何東西(沒有返回值)。

  • java對沒有自定義構造器的類提供默認構造器。若是自定義了任何一個構造器,則該類再也不具備默認構造器。

    2.方法重載

  • Java經過每一個相同函數名的獨一無二的參數類型列表來區分不一樣的重載方法。(參數順序的不一樣也能夠)

  • 不一樣的參數數據類型能夠做爲重載的方法,而數據類型又存在類型轉換的問題。方法重載時的類型專函遵循如下規則:

    1. 若是傳入的數據類型窄於方法中聲明的形式參數類型,那麼實際的數據類型就會被提高。如,info(float a){}函數,也能夠接受int型的參數,此時int型的參數自動提高爲float型。同理,char類型能夠以自動提高爲int類型。
    2. 若是傳入的數據類型寬於方法中聲明的形式參數類型,那麼就報錯了。須要程序員進行顯示顯式類型轉換。
    3. 返回值沒法區分函數重載。

3.this關鍵字

  • this關鍵字只能在方法內部使用,表示對」調用方法的那個對象」的引用。若是要在方法內部調用同一個類的另外一個方法,則沒有必要使用this。

  • 在類中函數一般經過返回this來返回當前對象的引用。

  • this關鍵字還能夠當作構造器來使用。可是在一個方法中只能指代一個構造器。見下面代碼:

    1. public class My0504 {
    2. My0504(int i) {
    3. System.out.println(i);
    4. }
    5. My0504(String s) {
    6. System.out.println(s);
    7. }
    8. My0504(int i, String s){
    9. this(i);//正確,至關於調用My0504(int i)
    10. this(s);//錯誤,此時this已經指代My0504(int i)
    11. }
    12. }
  • static方法中不能使用this,函數內仍是函數參數都不行。事實上,static方法中也只能直接調用static方法。

4.清理:finalize()和gc()

  • java容許在類中定義一個名爲finalize()的方法,它的工做原理」假定」是:一旦JVM中的垃圾回收器準備好釋放對象佔用的存儲空間,則其會首先調用該對象的finalize()方法。並在下一次垃圾回收動做發生時,真正的回收對象佔用的空間。
  • 理解finalize須要理解一下三點:
    1. 對象可能不被垃圾回收。
    2. 垃圾回收不等於」析構」。
    3. 垃圾回收只與內存有關。
  • system.gc()只是告訴垃圾收集器打算進行垃圾收集,而垃圾收集器進不進行收集是不肯定的。

5.垃圾回收工做機制

  • 詳見該書89-91頁。和wiz筆記的」Java 垃圾回收」。

6.成員初始化

  • 基本類型未初始化是否有初值?在函數內定義的未初始化的基本類型,沒有初值。在類內定義的未初始化的基本類型,擁有初值。分別是
類型 未初始化時的默認值
boolean false
char (char值爲0,顯示爲空白)
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
引用 null
    • 上述狀況說明,在類建立的過程,不管開發者有沒有指定,類內的成員變量都會進行初始化。若是用戶指定初始化,那麼須要注意初始化的順序問題:

      1. public class My0506 {
      2. int i = f();//正確
      3. int k = j;//錯誤,向前引用
      4. int f(){
      5. return 11;
      6. g();//正確
      7. }
      8. void g(){
      9. System.out.println("hello");
      10. }
      11. int j =11;
      12. }

      能夠看到,函數能夠不分順序的引用,可是成員變量的引用要注意定義的順序。

    • 上面討論了默認初始化、指定初始化,下面討論構造器初始化。

      1. public class Counter{
      2. int i;
      3. Counter(){
      4. i = 7;
      5. }
      6. }

      在上述類中i首先被初始化爲0,再被置爲7。

      構造器初始化要特別注意初始化順序的問題。簡而言之,就是類會優先執行默認初始化或者指定初始化,而後再執行構造器初始化。定義的前後順序並不影響該初始化順序。

相關文章
相關標籤/搜索