Java編程思想(后)
持有對象
- 如果一個程序只包含固定數量的且其生命期都是已知的對象,那么這是一個非常簡單的程序。
- Java中的庫基本類型: List, Set, Queue和Map --- 稱為集合類.
- ArrayList用add()插入對象, 用get()訪問這些對象。
- 如果一個類沒有顯式地聲明繼承那個類, 那么它自動繼承自Object.
- Java 泛型穿件類會非常復雜, 預定義的泛型會很簡單。
- 通過泛型, 可以在編譯器防止將錯誤類型的對象置到容器中。
- 泛型對應的是編譯器錯誤, 而不是運行時錯誤。
- foreach語法來選擇一個List中的每個元素。
- Object有默認的toString()方法。
- Java容器類庫的用途是保存對象:
- Collection: 一個獨立元素的序列, List, Queue, Set。
- Collection接口概括了序列的概念, 一種存放一組對象的方式。
- List不關心是否存在重復。
- Map: 一組成對的鍵值對對象, 允許使用鍵來查找值(字典)。
- Collection: 一個獨立元素的序列, List, Queue, Set。
- 任何容器類, 都必須有某種方式可以插入元素將他們再次取回, 持有事物是容器最基本的工作。
- 迭代器(也是一種設計模式): 是一個對象, 它的工作是變量並選擇序列中的對象, 而不用直到或關心序列底層的結構。
- 迭代器通常被稱為輕量級對象, 創建代價小。
- Java的Iterator只能單向移動, 這個Iterator只能用來:
- 使用方法iterator()要求容器返回一個Iterator, Iterator將返回序列的第一個元素。
- 使用next()獲得序列中的下一個元素。
- 使用hasNext()檢查序列中是否還有元素。
- 使用remove()將迭代器最近返回的元素刪除。
- iterator能夠將遍歷序列的操作與序列底層的結構分離。
- ListIterator是一個更強大的Iterator的子類型, 它只能用於各種List類的訪問。
- ListIterator可以雙向移動。
- LinkedList還添加了可以使其用作棧、隊列或雙端隊列的方法。
- 棧通常是指先進先出(LIFO)的容器, 有時棧也被稱為疊加棧, 最后壓入棧的元素, 第一個被彈出。
- Collection是描述所有序列容器的共性的根接口,它可能會被認為是一個附屬接口, 因為要表示其他若干個接口的共性而出現的接口。
java.util.AbstactCollection
類提供了Collection的默認實現。
通過異常處理錯誤
-
Java的異常處理機制建立在C++的基礎之上, 使用異常能夠降低錯誤處理代碼的復雜度。
-
異常機制能夠保證捕獲每個錯誤。
-
基本異常: 異常情形(exceptional condition)是阻止當前方法或作用域繼續執行的問題。
- 當拋出異常后, Java將使用new在堆上創建異常對象, 當前執行路徑被終止, 並且當前環境中彈出對異常對象的引用, 異常處理機制接管程序, 並開始尋找一個恰當的地方來繼續執行程序。--- 這個恰當的地方就是異常處理程序, 程序要么換一種方式運行, 要么繼續運行下去。
- 異常允許強制程序停止運行, 並告訴出現了什么問題, 或者強制程序處理問題, 並返回到穩定狀態。
- 所有異常類都有兩個構造器: 一個是默認構造器; 另一個是接受字符串作為參數, 以便把相關信息放入異常對象的構造器。
- 使用new創建了異常對象后, 此對象的引用將傳給throw。
- 可以把異常簡單地看作是一種不同的返回機制, 還能用拋出異常的方式從當前的作用域退出。返回一個異常對象, 然后退出方法或作用域。
- Throwable對象是異常類型的根類。
-
捕獲異常:
- 異常是如何被捕獲的, 必須首先理解監控區域(guarded region)的概念; --- 它是一段可能產生異常的代碼, 后面需緊跟處理這些異常的代碼。
- try塊: 如果在方法中拋出了異常, 這個方法將在拋出異常的過程中結束。
- catch塊: 異常處理程序, 每個catch子句(異常處理程序)看起來就像是接收一個且僅接收一個特殊類型參數的方法。
-
終止與恢復:
- 異常處理理論上有兩種基本模型: Java支持終止模型(Java和C++所支持的模型) --- 假設錯誤非常關鍵, 程序無法返回到異常發生的地方繼續執行, 一旦異常拋出,就表明錯誤已無法挽回, 也不能繼續執行。
- 恢復模型: 異常處理程序的工作是修正錯誤, 然后重新嘗試調用出問題的方法, 並認為第二次能成功。恢復模型通常希望異常被處理之后能繼續執行程序 --- 遇見錯誤時不能拋出異常, 而是調用方法來修正該錯誤。
- 或者把try塊放到while循環中, 直到得到滿意的結果。
- 異常處理理論上有兩種基本模型: Java支持終止模型(Java和C++所支持的模型) --- 假設錯誤非常關鍵, 程序無法返回到異常發生的地方繼續執行, 一旦異常拋出,就表明錯誤已無法挽回, 也不能繼續執行。
-
編譯器創建了默認構造器, 他講自動調用基類的默認構造器, 對異常來說, 最重要的部分是類名。
-
異常與記錄日志:
- Java可以使用呢
java.util.logging
工具將輸出記錄到日志中。
- Java可以使用呢
-
捕獲所有異常:
catch(Exception e) {System.out.println("Caught an exception");}
-
利用
throw e
重新拋出異常。 -
異常使用指南:
- 應該在下列情況下使用異常:
- 在恰當的級別處理問題。(在直到該如何處理的情況下才捕獲異常)。
- 解決問題並重新調用產生異常的方法。
- 進行少許修補, 然后繞過異常發生的地方繼續執行。
- 用別的數據進行計算, 以代替方法預計會返回的值。
- 把當前運行環境下能做的事情盡量做完, 然后把相同(不同)的異常重拋到更高層。
- 終止程序。
- 進行簡化。
- 讓類庫和程序更安全。
- 應該在下列情況下使用異常:
字符串
- 字符串操作是極端及程序設計中最常見的行為。
- String對象是不可變的, 每個方法都會創建一個全新的String對象, 以包含修改后的字符串內容。
- 重載'+'與StringBuilder: String對象具有只讀特性, 指向它的任何引用都不可能改變它的值。
- JDK自帶的工具javap可以反編譯代碼
javap -c Concatenation
--- 將生成JVM字節碼。 - Java中的每個類從根本上都是繼承自Object, 標准容器類自然也不例外。--- 都有toString()方法。
正則表達式
-
正則表達式已經整合到標准Unix工具集之中, 例如sed和awk, 正則表達式是一種強大而靈活的文本處理工具。
-
split()方法,其功能是將字符串從正則表達式匹配的地方切開。
-
\\
表示在正則表達式中插入一個普通(字面上的)反斜杠。 -
組是用括號來划分的正則表達式, 可以根據組的編號來引用每個組,0表示整個組, 1表示第一對括號里的組。
-
StringReader將String轉換可讀的流對象。
-
Scanner的構造器可以接受任何類型的輸入對象, 包括File對象, InputStream, String或者Readable對象。
- 有了Scanner, 所有的輸入, 分詞以及翻譯的操作都隱藏在不同類型的next方法中。
- Scanner類可以減輕輸入的負擔。
類型信息
- 運行時類型信息使得可以在程序運行時發現和使用類型信息。 --- RTTI(Run-Time Type Identification)。
- Class對象包含了與類有關的信息。 --- Class對象就是用來創建類的所有的常規對象的。
- Class類還擁有大量的使用RTTI的其他方式。
- 類是程序的一部分,每個類都有一個Class對象; 每當編寫並且編譯了一個新類,就會產生一個Class對象(被保存一個同名的.class文件中)。
- 為了生成這個類的對象,運行這個程序的Java虛擬機(JVM)將使用被稱為"類加載器"的子系統。
- 類加載器子系統實際上可以包含一條類加載器鏈,但是只有一個原生類加載器,它是JVM實現的一部分。
- 所有的類都是在對其第一次使用時, 動態加載到JVM中。創建第一個類的靜態成員的引用時, 就會加載這個類。
- new操作符創建類的新對象也會被當作對類的靜態成員的引用。
- Java程序在它開始運行之前並非被完全加載, 其各個部分是在必須時才加載的。
- 類加載器首先檢查一個類的Class對象是否已經加載, 如果尚未加載, 默認的類加載器就會根據類名查找
.class
文件。- 某個附加類加載器可能會在數據庫中查找字節碼。
- 類加載器首先檢查一個類的Class對象是否已經加載, 如果尚未加載, 默認的類加載器就會根據類名查找
- 類字面常量:
- Java還提供了另一種方法來生成對Class對象的引用, 即使用類字面常量
FancyToy.class
。 - 類字面常量不僅可以應用於普通的類,也可以應用與接口,數組以及基本數據類型。
- 另外,對於基本數據類型的包裝器類,還有一個標准字段TYPE。
- TYPE字段是一個引用,指向對應的基本數據類型的Class。
- TYPE字段是一個引用,指向對應的基本數據類型的Class。
- Java還提供了另一種方法來生成對Class對象的引用, 即使用類字面常量
- 為了使用類而做的准備工作實際包含三個步驟:
- 加載: 加載器執行,查找字節碼,並從字節碼中創建一個Class對象。
- 鏈接: 在鏈接階段將驗證類中的字節碼, 為靜態域分配存儲空間,如果必要的話,將解析這個類創建這個類對其他類的所有索引。
- 初始化: 如果這個類是超類(父類), 則對其初始化,執行靜態初始化器和靜態初始化塊。
- 初始化被延遲到對靜態方法(構造器隱式地是靜態的)或者非常數靜態域進行首次引用時才執行。
- 泛化的Class引用: class引用總是指向某個Class對象,可以制造類的實例, 並包含可用作與這些實例的所有方法代碼。
- Class引用表示的就是它所指向的對象的確切類型,而該對象便是Class類的一個對象。
- 利用cast方法進行轉型。
- instanceof與Class的等價性。
- RTTI的前提是, 這個類在編譯時必須是已知的。
- 動態代理。
- 空對象 --- null。
- interface關鍵字的一種重要目標就是允許程序員隔離構建, 進而降低耦合性。
- instanceof關鍵字返回一個布爾值,告訴我們對象是不是某個特定類型的實例。
- 工廠方法設計模式: 將對象的創建工作交給類自己去完成。
- 工廠方法可以被多態地調用, 從而創建恰當的對象。
泛型
- 一般的類和方法, 只能使用具體的類型: 要么是基本類型, 要么是自定義的類。如果要編寫可以應用於多種類型的代碼, 這種限制對代碼的約束會很大。
- 在面向對象編程中, 多態是一種泛化機制。
- final類不能擴展, 其他任何類都可以被擴展。
- 泛型實現了參數化類型的概念, 是代碼可以運用於多種類型, 希望類或方法具有最廣泛的表達能力。
- Java的泛型相比C++來說要弱很多。 --- 理解邊界所在,只有知道一個技術不能做什么,才能更好地做到所能做的。
- 元組(tuple):是將一組對象直接打包存儲於其中的一個單一對象,允許讀取其中元素,但不允許向其中存放新的對象。(數據傳送對象)。
- 泛型也可以應用於接口, 例如生成器(generator) --- 專門負責創建對象的類。
- 泛型的主要目的之一就是用來指定容器要持有什么類型的對象,而且由編譯器來保證類型的正確性。
- Java泛型的核心概念: 告訴編譯器想使用什么類型, 然后編譯器幫助處理一切細節。 --- 可以簡單地認為泛型和其他類型差不多,只是多了參數列表而已。
- 聲明為final的元素便不能再賦予其他值了。
- 基本類型不能作為泛型的類型參數。
- 創建一個適配器(adapter)來實現所需的接口。
- static方法,無法訪問泛型類的類型參數, 如果static方法需要使用泛型能力,就必須使其成為泛型方法。
- 在使用泛型類時, 必須在創建對象的時候指定類型參數的值,而使用泛型方法的時候,通常不必指明參數類型, 因為編譯器會自動找出具體的類型, --- 類型參數腿短(type arguement inference)。
- 編譯器能夠從泛型參數列表中的一個參數推斷出另一個參數。
- 泛型方法與可變參數能夠很好地共存。
- 生成某個類對象的類,必須具備兩個特點:
- 它必須聲明為public;
- 必須具備默認的構造器(無參數的構造其)。
- 泛型的一個重要好處是能夠簡單而安全地創建復雜的模型。
泛型方法
- 泛型方法使方法能夠獨立於類而產生變化。
- 使用泛型方法可以取代將整個類泛型化。
- 在泛型代碼內部,無法獲得任何有關泛型參數類型的信息。
- Java泛型重用了extends關鍵字。
- 無界通配符
<?>
看起來意味着任何事物, <?>可以被認為是一種裝飾。 - 混型的價值之一是它們可以將特性和行為一致地應用與多個類之上。
數組
- 數組與其他容器之間的區別有三方面: 效率, 類型和保存基類類型的能力.
- 數組是一種效率最高的存儲和隨機訪問對象引用序列的方式.
- ArrayList.
- 數組是第一級對象.
- 返回一個數組.
- 多維數組.
- 數組與泛型.
- Arrays實用功能.
容器深入研究
- 完整的容器分類法
- 散列與散列碼 --- HashMap.
Java I/O系統
- File類
- Reader和Writer.