Java程式設計語言(第4版) 筆記

來源:互聯網
上載者:User

The Java Programming Language (Four Edition)


第一章  快速探索
第二章  類與對象
第三章  類的擴充
第四章  介面
第五章  嵌套類和介面
第六章  枚舉類型
第七章  語言符號、值和變數
第八章  封裝器類
第九章  運算子和運算式
第十章  控制流程

第十一章  泛型型別

第十二章  異常和斷言

第十三章  字串與Regex

第十四章  線程

第十五章  註解

第十六章  反射

第十七章  記憶體回收行程與記憶體

第十八章  包

第十九章  文檔注釋

第二十章  I/O 包

第二十一章  集合

第二十二章  各種常用工具

第二十三章  系統編程

第二十四章  國際化和本地化

第二十五章  標準包

第一章  快速探索

第二章  類與對象

2.1、靜態欄位
    將欄位聲明為 static(靜態欄位),會使該欄位只有一個執行個體,並且該執行個體能被該類的所有對象共用。
    而且無論建立了該類的多少個執行個體,這個欄位的都只有一份(記憶體中唯一?)。

2.2、初始化塊
    欄位另一種更複雜的初始化方式就是使用初始塊。
    初始塊是一段出現在類聲明中的語句塊,它位於所有成員、構造器以及聲明之外,它可以初始化對象的欄位。
    它們會被優先執行,就像它們放置在類的每一個構造器的開頭那樣,如果有多個塊,它們會按照在類中出現的先後順序執行。
    只有當類的所有構造器都聲明會拋出某個檢查型異常時,它的初始塊才可以拋出該異常。
    應該審慎的使用初始塊,用它們來表示那些構造器不能單獨輕易完成的工作。

例如
    public long idNum;
    private static long nextID = 0;

    {
        idNum = nextID++;
    }

2.3、靜態初始化
    靜態初始塊被聲明為 static,只能引用類的靜態成員,不能拋出任何檢查型異常。

    類內部的初始化順序是從前到後的,即代碼中的“欄位初始化器”或“初始塊”都是按照從頭到尾的順序執行。

例如:要確保靜態欄位 kk 在被訪問前已初始化。
    static int kk = 9;
   
    static{
        System.out.println("1");       
    }
   
    static{
        System.out.println(kk);       
    }

2.4、參數值
    準確的講,Java 只有一種參數傳遞方式,即值傳遞,這樣有利於保持簡單,傳遞的也只是這個值的副本。

2.5、使用方法來控制訪問
    控制內部資料訪問的方法有時被稱為存取方法(accessor method),使用它們可以增強類資料的封裝性。

第三章  類的擴充

3.1、擴充類的構造器
    擴充類的構造器必須通過隱式或顯式地調用其超類的構造器,將繼承而來的欄位的構造工作委託給超類。
構造器的順序依賴:
    1、調用其超類的構造器(同樣 3步順序遞迴調用到 Object);
    2、用這些欄位的初始器和初始化塊來初始化它們;
    3、執行構造體。

3.2、繼承與重定義成員
    ● 重載(overloading):提供多個具有相同名字的方法,但是它們擁有可以彼此區分開的不同簽名。
    簽名是由方法名及其參數的類型和數量組成的,它並不包含傳回型別或者拋出的異常列表,並且我們無法基於這些因素來重載方法。
    不同重載的方法可以有不同類型的傳回值。

    ● 重寫(overriding):將方法的超類實現替換為自己的實現。其簽名必須相同,但是他們的傳回型別可以按照某種方式變換。
    1、簽名(方法名、參數類型和個數)必須相同。
    2、傳回型別:參考型別的可以返回超類所聲明的子類(is a 關係),基本類型的返回必須相同。
    3、存取修飾詞:可以改變,但只能提供更多的存取權限,否則違反契約(不能替代超類實現)。
    4、可以改變其他方法修飾符(synchronized、native和strictfp),static 則是必須保持一致,final 可以修飾重寫的方法(超類被重寫的方法則不能是 final)。
    5、throws 子句:重寫 throws 子句可以少於超類所列出的數量、或者更為具體,還可以沒有任何 throws 子句。但是不能比超類的範圍廣(必須是多態相容的)。
    6、私人的方法:對於超類的 private 方法,子類沒有重寫,對私人方法的調用總會調用當前類中所聲明的方法實現。

例如:
    public static void name() throws IndexOutOfBoundsException {....}

正確的重寫:    public static void name() {....}

錯誤的重寫:    public static void name() throws ClassNotFoundException {....}

3.3、相容類型的實現
    ● 向上轉型:向繼承結構高端轉換,其線程是安全的。
    ● 向下轉型:向繼承結構低端轉換,非安全線程。

     instanceof 操作符檢測一個對象所輸入的類,傳回值為 false/true,常用語安全的將一個引用向下轉型。
例:if (sref instanceof More)
        mref = (More) sref;

第四章  介面

4.1、抽象類別與抽象方法
    通過使用抽象類別,我們可以聲明只定義了部分實現的類,而讓擴充類去提供其部分方法或者全部方法的具體實現。
    任何擁有 abstract 方法的類都必須聲明為 abstract。
    不能建立抽象類別的對象,應為某些可能會被調用的方法沒有任何有效實現。
    不能是 static 因為 static 不能是 abstract 的。

4.2、介面
    介面是純設計的表現形式,而類則是設計和實現的混合物。
    介面類型的引用只能提供者成員。    Exam xxx = new ImplExam();
    ● 介面常量:隱式 public final static,必須有初始器(值)。
    ● 介面方法:隱式 public abstract,除註解外不允許有其他方法修飾符(如 synchronized、native和strictfp 等用於定義實現細節的修飾符);不能是 final 因為它還沒有被實現;不能是 static 因為 static 不能是 abstract 的。

4.3、擴充介面
    可以使用 extends 擴充介面(介面繼承介面),介面支援多重繼承其他介面。

    public interface C extends A, B {....}

    ● 繼承和隱藏常量
        1、新聲明常量都將隱藏繼承而來的常量。
        2、繼承而來的常量可以使用該常量完全限定名訪問(X.val,常見引用 static 成員形式)。
        3、一個介面繼承了兩個或者多個名字相同常量,那麼該常量所有簡單引用都具有二義性,會導致編譯出錯。所以,必須顯式使用介面常量,例如 X.val 和 Y.val 等等。   
        4、在繼承一個類的同時還實現了多個介面,也可能會遇到二義性的問題。

    ● 繼承、覆蓋和重載方法
        1、一個介面同時實現了兩個簽名相同的方法,只會有一個這樣的方法存在,不會有二義性。
        2、遇到簽名相同,返回不同的方法,除非某些返回的類型是其他的子類型,否則不同的返回會產生二義性。

4.4、介面的應用
    任何一個希望被繼承的主要類,不管是否抽象類別,都應該是一個介面的實現。(同樣是 is a 的關係,繼承只能擴充一個,但是介面能實現多個。)

第六章  枚舉類型
    枚舉是一個特殊的類,它要表示的每一個具名常量都有與之對應的預定義執行個體。

第七章  語言符號、值和變數

第八章  封裝器類

8.1、封裝器類構造
    每一個封裝器為它所指的基本類型定義一個不可改變對象。
例如: new Integer(1);    建立對象,他的值始終保持1,不可改變其值。

8.2、裝/拆箱轉換
    Integer val = 3;
    int x = val.intValue();
    裝/拆箱轉換需分配一個封裝器類執行個體,這樣會消耗記憶體。

    由於封裝器類是不可變的,所以兩個擁有相同值的對象在一定範圍是可以互換使用的(數值型為 -128~127)。
例如:
        public static boolean sameArgs(Integer a, Integer b) {
        return a == b;        //判斷是否對象相同
    }

true    sameArgs(12, 12);
false    sameArgs(12, new Integer(12));
false    sameArgs(1280, 1280);

第九章  運算子和運算式

9.1、類型轉換
    ● 隱式拓寬:將整形轉換為浮點型,反之則不可以,整形轉換浮點型不會產生精度丟失現象。
        長整型 long --> (隱式轉換)float  -->  (強制轉換)long   也是可行的,但會丟失精度。

    ● 顯式強制類型轉換
        1、浮點數轉換為整數時,小數點後的部分會捨去。
        2、double 強制轉換 float 可能會發生:a.精度丟失;b.得到0;c.或者大於 float 型範圍,得到無窮大。
        3、整數間轉換,通過捨去高位,從而有可能被動改變符號。

9.2、運算子優先順序
    用括弧將運算子括起來,可提高可讀性並確保正確的優先順序。

第十章  控制流程

10.1、增強 for 語句

    for(Type loop-variable : set-expression)
        statement

    ● 對於數組:使用 for-each 的優點在於不必使用數組下標,缺點是只能查看,不能修改數組元素。
    ● 對於元素集合:迭代的元素提供簡答文法結構,但不能同時迭代多個集合。
    ● 不是同步的,非安全執行緒的。

10.2、標號


    label: statement

    利用標號命名語句,在配合 break lable; 和 continue lable; 將控制流程轉到嚴格受限的地方。


第十一章  泛型型別


第十二章  異常和斷言


12.1、斷言(assertion)

    用來檢查永遠都應該是 true 的情況,如果發現斷言是 false,就會拋出異常。添加測試斷言可以為我們提供一種在程式中的錯誤引發奇怪後果前捕獲它們的途徑。

    文法:    assert eval-expr [: detail-expr]

    在斷言被關閉時(預設情況下),斷言是不被計算了。所以 :
assert ++i < max;    ++i 塊有可能不會起作用,建議分開寫。

    斷言應該用來測試從來不發生的情況,因為斷言會拋出 Error 而不是 Exception。然而,使斷言成為必須會使代碼的運行環境變得複雜,因為當前斷言的開啟及關閉間反覆操作會帶來複雜性,所以不建議使用。


第十三章  字串與Regex


13.1、Regex的匹配

    java.util.regex 包提供 Regex(regular expression)用於“檢測字串是否和某種模式比對”或者“挑選字串中各個部分”。

    ● 重用已編譯的模式:執行匹配所涉及的所有狀態都駐留在匹配器中,所以多個匹配器可以共用同一模式。
    Pattern p = Pattern.compile(regularExpression);    //將給定的Regex編譯到模式中
    Matcher m = p.matcher(sequence);        //利用輸入序列從模式建立匹配器
    boolean b = m.matches();            //嘗試將整個輸入序列與該模式比對

    ● 僅使用一次Regex
    boolean b = Pattern.matches(regex, sequence);    //編譯給定Regex並嘗試將給定輸入與其匹配
   


13.2、Regex的替換

    通過調用模式的 matcher 方法從模式建立匹配器。建立匹配器後,可以使用它執行三種不同的匹配操作:

    ● matches 方法嘗試將整個輸入序列與該模式比對。
    ● lookingAt 嘗試將輸入序列從頭開始與該模式比對。
    ● find 方法掃描輸入序列以尋找與該模式比對的下一個子序列。

    每個方法都返回一個表示成功或失敗的布爾值。通過查詢匹配器的狀態可以擷取關於成功匹配的更多資訊。

ps.Regex本身複雜,只有在確實需要的情況下才使用它。在使用的時候,盡量確保模式的清晰度。


第十四章  線程
    在電腦中每次執行一步的操作序列被稱為線程(thread),而這種單線程編程模型正是大多數程式員所使用的模型。線程可以獨立於其他線程執行一項任務,線程間也可以共用訪問對象。當兩個線程在修改同一塊資料時,如果它們是會對資料造成破壞的交叉方式去執行,那麼就會出現競爭危機,解決的方法是利用一個鎖和對象關聯起來,這個鎖可以告知該對象是否正在被使用。

14.1、建立線程
    ● 擴充 Thread 類來建立新的線程,重寫 run 方法。
    class PrimeThread extends Thread {
         long minPrime;
         PrimeThread(long minPrime) {
             this.minPrime = minPrime;
         }
 
         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }

下列代碼會建立並啟動一個線程:
     PrimeThread p = new PrimeThread(143);    //建立該類執行個體
     p.start();        //啟動線程,JAVA 虛擬機器調用該線程的 run 方法。

    ● 聲明實現 Runnable 介面的類。該類然後實現 run 方法。
     class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(long minPrime) {
             this.minPrime = minPrime;
         }
 
         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }

下列代碼會建立並啟動一個線程:
     PrimeRun p = new PrimeRun(143);    //分配該類對象
     new Thread(p).start();        //利用物件建構一個新的線程,並啟動

    ps.每個線程都有一個標識名,多個線程可以同名。如果線程建立時沒有指定標識名,就會為其產生一個新名稱。


14.2、隱藏線程的 run 方法

    run 方法是公用的,為了防止用戶端私自調用該方法,我們可以不起實現 Runable 介面,而是定義一個內部的 Runable 對象,確保不被濫用。例如:

  public class Ping2 {
    public Ping2() {
        Runnable service = new Runnable(){
            public void run() {
                //......
            }
        } ;
       
        new Thread(service).start();
    }
  }


14.3、線程的結束

    有三種情況可使線程終止:
    ● run 方法正常返回(常規方式)
    ● run 方法意外結束
    ● 應用程式終止

    Thread.currentThread().interrupt(); 向線程發送中斷:中斷一個線程通常不會影響它正在執行的操作,但是像 sleep 和 wait 這樣會拋出 InterruptedException 異常的方法除外。
 
    一個線程可以使用某種形式的 join 方法來等待另一個線程終止。

    不要使用 stop 方法:首先因為 stop 不能強制終止任何線程,無力對付惡意方法;其次,stop 會影響同步鎖,破壞對象。所以建議轉而使用 interrupt 方法。


14、4 同步

    當多線程使用同一個對象時,存在著由於交叉操作而破壞資料的可能性,所以在某些動作操作對象之前,必須先獲得對象的鎖來阻止其他對象獲得這個鎖,直至它被持有人釋放為止。

    利用 synchronized 的聲明,我們可以確保多個啟動並執行線程不會互相干擾,因為每一個方法都將互斥地執行(在該方法調用結束前不能被其他方法調用)。

    安全執行緒:多個線程可以並發調用對象上的方法,並且在每個線程中被調用的方法都在執行所期望的作業。


第十五章、註解

    註解以結構化的方式提供了程式及其元素(類、方法、欄位、變數等等)的資訊,這些資訊能夠被外部工具自動處理。


第十六章  反射


第十七章  記憶體回收行程與記憶體

    JAVA 虛擬機器可以使用一種稱為記憶體回收(garbage collection)的技術來確定對象在程式中何時不再被引用,因此它可以安全地釋放對象佔用的記憶體空間。

    當我們從任何可執行代碼都無法到達某個對象時,它所佔的空間就可以被回收。記憶體回收會佔用一定的系統資源,通常情況下,只有需要更多的記憶體空間或者避免發生記憶體溢出時,記憶體回收行程才會運行。但是程式可能沒有發生記憶體溢出,甚至在沒有接近記憶體退出的時候就退出了,所以可能根本不需要執行記憶體回收。

    記憶體回收並不能保證記憶體中總是會有空間來建立新對象,不停的建立對象共置於使用列表中,就會造成記憶體流失。記憶體回收解決了很多(但並非全部)的記憶體配置問題。
   
    System.runFinalization();    //運行掛起 finalization 的所有對象的終止方法      
    System.gc();            //運行記憶體回收行程

    Runtime.getRuntime().runFinalization();
    Runtime.getRuntime().gc();


第十八章  包


18.1、匯入機制

    如果聲明了一個對 Xxx 類的引用,那麼編譯器就會按照下面的順序搜尋該類型:
    1、包括繼承類型在內的當前類型。
    2、當前類型的巢狀型別。
    3、顯式命名的匯入類型(單類型匯入, import attr.Attributed;)
    4、在同一個包中聲明的其他類型。
    5、隱式命名的匯入類型(按需匯入,import attr.*;)

    為了避免匯入同名的兩個類型產生二義性,建議使用完全限定名。


第十九章  文檔注釋

19.1、剖析文檔注釋
    /**
     * 文檔注釋第一句應該是一個良好的摘要。
     * 文檔注釋中可以嵌套標準的 HTML 標籤,用于格式指令或連結到其他文檔。
     * 如果想使用 @ 字元,請使用 @,否則會被當作文檔注釋標籤的開始。
    */
   



第二十章  I/O 包

    java.io 包是用流(stream)定義 I/O 的,流是有序的資料序列,它有一個源(輸入資料流)和目的地(輸出資料流)。
    java.nio 包是用緩衝區(buffer)和通道(channel)定義 I/O 的,它用於高輸送量伺服器。
    java.net 包基於對通訊端的使用,用一種基於流或通道的模型提供對網路 I/O 的特殊支援。


20.1、流的概述

    I/O 主要有兩部分:
    ● 字元流(character stream,16位的 UTF-16 字元),它基於文本的 I/O,有讀取器(reader)和寫入器(write)。
    ● 位元組流(byte stream,通常是 8位),它基於資料的 I/O,有輸入資料流(input stream)和輸出資料流(output stream)。

    轉換流 InputStreamReader 與 OutputStreamWriter 可以通過指定或者預設的編碼機制在 字元流 與 位元組流 之間互相轉換,類似於“黏合劑”,使我們可以以一種統一的、平台無關的方式使用現有的 8位字元編碼機制去處理本地字元集。
    InputStreamReader 對象讀取位元組,並使用適合該流的編碼機制將其轉換為字元。
    OutputStreamWriter 對象將接受提供的字元,使用適合的編碼機制將它們轉換為位元組。
    (註:無 ReaderStreamInput 類將字元轉換為位元組,也無 WriterOutputStream 這個類將位元組轉譯為字元)

    InputStreamReader(InputStream in);
    OutputStreamWriter(OutputStream out);
    關閉轉換流的同時也會關閉掉將其關聯的位元組流,所以一定要謹慎。


20.2、資料位元組流

    通過流來傳輸特定類型的位元據。DataInput 和 DataOutput。


20.3、對象序列化

    將對象的表示轉換為位元組流的過程成為序列化,而從位元組流中重構一個對象的過程被稱為還原序列化。
    當 ObjectOutputStream 寫入序列化對象是,該對象必須實現 Serializable 介面,聲明該類為可序列化的。


第二十一章  集合


21.1、迭代

    對 Collection 使用 iterator 方法將獲得一個 Iterator 對象,這個對象可以遍曆集合內容,而且每次都只能訪問一個元素。
    與增強型 for 迴圈相比,它可以通過 remove 方法移除元素,這種方式是安全的。


21.2、同步

    java.util 包中提供的所有集合實現都是非同步的(除了 Vector、Dictionary、Hashtable 等遺留下來的集合)。


第二十二章  各種常用工具

    ● Formatter:用於產生格式化文本。
    ● Random:用以產生偽隨機數序列的類。
    ● Scanner:該類用於掃描文本,並根據Regex模式將其解析成基礎資料型別 (Elementary Data Type)或者字串。
    ● Timer/TimerTask:用於調度將來某個時刻運行任務的一種方式(包括重複發生),每個 Timer 對象都有一個相關聯的線程。


第二十三章  系統編程

    應用程式有時必須同 JAVA 虛擬機器的運行時系統或底層作業系統進行互動。java.lang 中有三個主要的類提供了這個訪問:


23.1、System 類

    System 類提供了用於操縱系統狀態的的靜態方法,並起到了資源倉庫的作用。它有四個通用領域的功能性:
    ● 標準 I/O 流
    ● 操縱系統屬性
    ● 用於訪問當前 Runtime 對象的工具方法和便利方法。
    ● 安全性


23.2、Runtime 類

    提供了訪問虛擬機器的運行時系統的介面。當前 Runtime 對象提供了對每個運行時系統的功能進行互動的能力,例如與記憶體回收行程互動、執行其他程式及關閉運行時系統。


23.3、Process 類

    表示的是正在啟動並執行進程,它是通過調用 Runtime.exec 來執行另一個程式時建立的,也可以通過直接使用 ProcesssBuilder 對象來建立。


第二十四章  國際化和本地化


24.1、地區

    java.util.Locale 對象描述了地區。


24.2、資源束

    java.util.ResourceBundle 類。


24.3、貨幣

    java.util.Currency 類可以協助我們正確格式化貨幣值。


24.4、時間、日期、日曆

    時間是用長整型 long 表示的,從 1970 年開始,可以通過 java.util.Date 類獲得時間,時間的比較可以用 before 和 after 方法,或者可以用 getTime/setTime 方法獲得/設定時間的 long 型值。Date 沒有提供本地化支援,我們可以使用更有效複雜的地區敏感的 Calendar 和 DateFormat 類來代替它。

    抽象類別 Calendar 表示不同標記時間的方式,同時也提供了許多用的日曆欄位。
    GregorianCalendar 類表示日曆。
    SimpleDateFormat 類格式化、解析時間的類。
例:
    Calendar cal = new GregorianCalendar(1972, Calendar.OCTOBER, 26);
    System.out.println(cal.getTime());


第二十五章  標準包
    ● java.awt:抽象工具箱的抽象層,用來編寫平台無關的圖形化使用者介面。
    ● java.applet:Applet 類和相互關聯類型,用於編寫可嵌入其他應用程式的子程式,如 HTML 瀏覽器。
    ● java.beans:用於編寫用戶端可重用的 JavaBeans 構件。
    ● java.lang.instrument:用於定義代理的服務。
    ● java.lang.managerment:用於監視並管理其所在的虛擬機器以及作業系統服務。
    ● java.math:數學
    ● java.net:網路
    ● java.rmi:遠程方法調用
    ● java.security 與相關的工具包:安全工具。
    ● java.sql:關聯式資料庫訪問

    ● javax.* :標準擴充工具包
    ● javax.sound:建立和操作聲音的子包。
    ● javax.swing:GUI構建的 Swing 包。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.