《Java學習筆記JDK8》學習總結

chapter 6   繼承與多態

 6.1何謂繼承

1.繼承的定義:繼承就是避免多個類間重複定義共同行爲。javascript

2.總結:教材中經過設計一款RPG遊戲的部分代碼向咱們展現了「重複」程序代碼的弊端,爲了改進,咱們引進了繼承的概念。在咱們自我學習的過程當中,經過一次次的改進,也曾經獲得這樣的啓示:在不一樣的信息類中,有多少的屬性就設置多少個變量,給每一個屬性分別給予設置和獲取的方法,以來能夠將屬性設爲private時仍然能夠存取引用數據,二來當多個類擁有一樣屬性和一樣的設置、獲取方法時,咱們能夠將其利用繼承於父類的方式精簡代碼,提升可讀性和簡潔性,並未以後對代碼的修改提供方便。html

簡而言之,就是須要咱們經過理解和提煉,將相同的程序代碼提高爲父類。java

3.繼承的格式:咱們經過關鍵字「extends」來鏈接子類和父類,這表示子類會擴充、繼承父類的行爲。linux

4.引入類圖:類圖是用於建模幫助咱們理解類中內容、父類子類間關係的工具,在教材161頁有提示,另外在畢向東老師Java講解視頻中也有說起,而且更爲詳細。設計模式

5.is-a:繼承中,子類與父類間會有is-a的短息,即「是一種」的關係。簡單說就是:子類是父類的一種。教材中經過劍士(子類)是一種角色(父類)的例子來講明。數組

此處引入了編譯與運行的經過判斷的講解,在這當中說起了一個操做:「如何讓編譯程序閉嘴」。這實際上是一種投機的操做,編譯雖然可以無錯誤地經過,但運行結果要自負。

6.重載:在並行的類中定義同名方法,這就是重載方法的運用。安全

7.多態:引入多態,實際上是對重載的改進。當並行類不少而且他們擁有共同的特色時,咱們能夠將其運用繼承修改代碼,並在此基礎上引入多態。多態其實就是使用單一接口操做多種類型的對象。這種寫法的好處就是可以具備更高的可維護性。數據結構

8.從新定義:在繼承父類以後,定義於父類中相同的方法不熟,但執行內容不一樣,這就是從新定義(Override)。jvm

技巧:在某個子類中某個方法前標註@Override,表示要求編譯程序檢查,該方法是否是真的從新定義了父類中國某個方法,若不是,則編譯錯誤。

9.抽象方法:若是某方法區塊中沒有任何程序代碼操做,可使用abstract表示該方法爲抽象方法,該方法不用撰寫{}區塊,至二級用「;」結束便可。ide

10.抽象類:若一個類中有方法沒有操做而且表示爲abstract,則這個類就不能用來生成實例,便是抽象類,要在class前面表示abstract。

11.抽象類的繼承:若子類繼承抽象類,對於抽象方法有兩種作法:一是繼續標示該方法爲abstract,該子類所以也是一個抽象類,必須在class前面表示abstract;另外一種作法就是操做抽象方法。若兩種作法都沒有實施,就會引起編譯錯誤。

6.2繼承語法細節

1.protected:

(1)private定義的屬性不能直接在子類中存取,只能經過獲取方法來取得。若只想讓子類能夠直接存取屬性變量又不想徹底開放訪問權限時,可將他們定義爲protected。

(2)被聲明爲protected的成員,相同包中的類能夠直接存取,不一樣包中的類須要在繼承後的子類中存取。

(3)在寫程序時,若一開始對權限未知,通常將成員設定爲private。

2.從新定義的細節

(1)super:若子類想取得父類中的方法定義,可在調用方法前,加上super關鍵字。(例見Game6 Role.java;Game6 SwordsMan.java;Game6 Magician.java)

(2)注意:可使用super關鍵字調用的父類方法,不能定義爲private。而且對於父類中的方法權限,只能擴大但不能縮小。

(3)JDK5的改進:在JDK5以前,從新定義方法時除了能夠定義權限較大的關鍵字外,其餘部分必須與父類中方法簽署徹底一致,例如返回值類型。在JDK5及以後,只要返回類型是父類中方法返回類型的子類,也是能夠經過編譯的。

(4)提示:static方法屬於類擁有,若是子類中定義了相同簽署的static成員,該成員屬於子類全部,而非從新定義,static方法也沒有多態,由於對象不會個別擁有static成員。

3.構造函數:

(1)繼承構造函數定義的前後順序:建立子類石磊後,會先進行父類定義的初始流程再進行子類中定義的初始流程。即在建立子類實例後,會先執行父類構造函數定義的流程,再執行子類構造函數定義的流程。

(2)構造函數的重載:父類中可重載多個構造函數,若是子類構造函數中沒有指定執行父類中哪一個構造函數,會默認調用父類中無參數的構造函數。

(3)this()和super()只能擇一調用,並且必定要在構造函數第一行執行。

4.final關鍵字

(1)final:若是對象數據成員被聲明爲final,但沒有明確使用=指定值,表示延遲對象成員值的指定,在構造函數執行流程中,必定要有對該數據成員指定值得操做,不然編譯錯誤。

(2)繼承中的final:若class前使用了final,則這個類是末類,不能被繼承。若方法被限定爲final,子類也不能從新定義final方法了。

5.java.lang.Object:若是定義類時沒有使用extends關鍵字定義繼承任何類,則表明它繼承java.lang.Object。即它是全部類的最上層父類。

6.垃圾收集:對於再也不有用的對象,JVM有垃圾收集機制,收集到的垃圾對象所佔據的內存空間會被垃圾收集器釋放。在執行流程中,沒法經過變量參考的對象,就是GC認定的垃圾對象。

7.抽象類:重點經過例子體現繼承思想。(代碼包中有對應代碼)

附加:總結補充

經過我對Java視頻的複習,我將繼承與多態相關知識點記錄以下:


1.繼承的優勢:

(1)提升了代碼的複用性。
(2)讓類與類之間產生了關係,提供了另外一個特徵多態的前提。

2.父類的由來:實際上是由多個類不斷向上抽取共性內容而來的。java中對於繼承,java只支持單繼承。java雖然不直接支持多繼承,可是保留了這種多繼承機制,進行改良。

單繼承:一個類只能有一個父類。
多繼承:一個類能夠有多個父類。

3.不支持多繼承的緣由:當一個類同時繼承兩個父類時,兩個父類中有相同的功能,那麼子類對象調用該功能時,運行哪個呢?由於父類中的方法中存在方法體。可是java支持多重繼承。A繼承B,B繼承C,C繼承D。多重繼承的出現,就有了繼承體系。體系中的頂層父類是經過不斷向上抽取而來的。它裏面定義的該體系最基本最共性內容的功能。因此,一個體系要想被使用,直接查閱該系統中的父類的功能便可知道該體系的基本用法。那麼想要使用一個體系時,須要創建對象。建議創建最子類對象,由於最子類不只可使用父類中的功能。還可使用子類特有的一些功能。

簡單說:對於一個繼承體系的使用,查閱頂層父類中的內容,建立最底層子類的對象。

4.子父類出現後,類中的成員的特色:

(1)成員變量:子父類中出現同樣的屬性時,子類類型的對象,調用該屬性,值是子類的屬性值。若是想要調用父類中的屬性值,須要使用一個關鍵字:super 。

This:表明是本類類型的對象引用。
Super:表明是子類所屬的父類中的內存空間引用。

注意:子父類中一般是不會出現同名成員變量的,由於父類中只要定義了,子類就不用在定義了,直接繼承過來用就能夠了。

(2)成員函數:當子父類中出現瞭如出一轍的方法時,創建子類對象會運行子類中的方法。好像父類中的方法被覆蓋掉同樣。因此這種狀況,是函數的另外一個特性:覆蓋(複寫,重寫)。當一個類的功能內容須要修改時,能夠經過覆蓋來實現。

(3)構造函數:發現子類構造函數運行時,先運行了父類的構造函數。緣由是子類的全部構造函數中的第一行,其實都有一條隱身的語句super();

注意:子類中全部的構造函數都會默認訪問父類中的空參數的構造函數,由於每個子類構造內第一行都有默認的語句super(); 若是父類中沒有空參數的構造函數,那麼子類的構造函數內,必須經過super語句指定要訪問的父類中的構造函數。若是子類構造函數中用this來指定調用子類本身的構造函數,那麼被調用的構造函數也同樣會訪問父類中的構造函數。

5.繼承的細節:

在方法覆蓋時,注意兩點:

子類覆蓋父類時,必需要保證,子類方法的權限必須大於等於父類方法權限能夠實現繼承。不然,編譯失敗。
覆蓋時,要麼都靜態,要麼都不靜態。 (靜態只能覆蓋靜態,或者被靜態覆蓋)

6.繼承的弊端:打破了封裝性。對於一些類,或者類中功能,是須要被繼承,或者複寫的。此時則須要引進final來解決。

7.final特色:

這個關鍵字是一個修飾符,能夠修飾類,方法,變量。
被final修飾的類是一個最終類,不能夠被繼承。
被final修飾的方法是一個最終方法,不能夠被覆蓋。
被final修飾的變量是一個常量,只能賦值一次。

其實這樣的緣由的就是給一些固定的數據起個閱讀性較強的名稱。
不加final修飾不是也可使用嗎?那麼這個值是一個變量,是能夠更改的。加了final,程序更爲嚴謹。常量名稱定義時,有規範,全部字母都大寫,若是由多個單詞組成,中間用 _ 鏈接。

8.抽象類 abstract:
抽象:不具體,看不明白。抽象類表象體現。
在不斷抽取過程當中,將共性內容中的方法聲明抽取,可是方法不同,沒有抽取,這時抽取到的方法,並不具體,須要被指定關鍵字abstract所標示,聲明爲抽象方法。
抽象方法所在類必定要標示爲抽象類,也就是說該類須要被abstract關鍵字所修飾。

9.抽象類的特色:

抽象方法只能定義在抽象類中,抽象類和抽象方法必須由abstract關鍵字修飾(能夠描述類和方法,不能夠描述變量)。
抽象方法只定義方法聲明,並不定義方法實現。
抽象類不能夠被建立對象(實例化)。
只有經過子類繼承抽象類並覆蓋了抽象類中的全部抽象方法後,該子類才能夠實例化。不然,該子類仍是一個抽象類。

10.抽象類的細節:

(1)抽象類中是否有構造函數?有,用於給子類對象進行初始化。
(2)抽象類中是否能夠定義非抽象方法?
能夠。其實,抽象類和通常類沒有太大的區別,都是在描述事物,只不過抽象類在描述事物時,有些功能不具體。因此抽象類和通常類在定義上,都是須要定義屬性和行爲的。只不過,比通常類多了一個抽象函數。並且比通常類少了一個建立對象的部分。
(3)抽象關鍵字abstract和哪些不能夠共存?final ,	private , static 
(4)抽象類中可不能夠不定義抽象方法?能夠。抽象方法目的僅僅爲了避免讓該類建立對象。

chapter7 接口與多態

1.定義:關鍵字interface。接口中包含的成員,最多見的有全局常量、抽象方法。

注意:接口中的成員都有固定的修飾符。
成員變量:public static final
成員方法:public abstract
interface Inter{
   public static final int x = 3;
   public abstract void show();
}

3:接口中有抽象方法,說明接口不能夠實例化接口的子類必須實現了接口中全部的抽象方法後,該子類才能夠實例化。不然,該子類仍是一個抽象類。

4:類與類之間存在着繼承關係,類與接口中間存在的是實現關係。繼承用extends  ;實現用implements ;

5:接口和類不同的地方,就是,接口能夠被多實現,這就是多繼承改良後的結果。java將多繼承機制經過多現實來體現。

6:一個類在繼承另外一個類的同時,還能夠實現多個接口。因此接口的出現避免了單繼承的侷限性。還能夠將類進行功能的擴展。

7:其實java中是有多繼承的。接口與接口之間存在着繼承關係,接口能夠多繼承接口

接口都用於設計上,設計上的特色:(能夠理解主板上提供的接口)

1:接口是對外提供的規則。
2:接口是功能的擴展。
3:接口的出現下降了耦合性。

抽象類與接口:

抽象類:通常用於描述一個體系單元,將一組共性內容進行抽取,特色:能夠在類中定義抽象內容讓子類實現,能夠定義非抽象內容讓子類直接使用。它裏面定義的都是一些體系中的基本內容。

接口:通常用於定義對象的擴展功能,是在繼承以外還需這個對象具有的一些功能。

抽象類和接口的共性:都是不斷向上抽取的結果。

抽象類和接口的區別:

1:抽象類只能被繼承,並且只能單繼承。
接口須要被實現,並且能夠多實現。
2:抽象類中能夠定義非抽象方法,子類能夠直接繼承使用。
接口中都有抽象方法,須要子類去實現。
3:抽象類使用的是  is a 關係。
接口使用的 like a 關係。
4:抽象類的成員修飾符能夠自定義。
接口中的成員修飾符是固定的。全都是public的。

在開發以前,先定義規則,A和B分別開發,A負責實現這個規則,B負責使用這個規則。至於A是如何對規則具體實現的,B是不須要知道的。這樣這個接口的出現就下降了A和B直接耦合性。 

chapter8 異常

1.異常:就是不正常。程序在運行時出現的不正常狀況。其實就是程序中出現的問題。這個問題按照面向對象思想進行描述,並封裝成了對象。由於問題的產生有產生的緣由、有問題的名稱、有問題的描述等多個屬性信息存在。當出現多屬性信息最方便的方式就是將這些信息進行封裝。異常就是java按照面向對象的思想將問題進行對象封裝。這樣就方便於操做問題以及處理問題。

2.出現的問題有不少種,好比角標越界,空指針等都是。就對這些問題進行分類。並且這些問題都有共性內容好比:每個問題都有名稱,同時還有問題描述的信息,問題出現的位置,因此能夠不斷的向上抽取。造成了異常體系

--------java.lang.Throwable

Throwable可拋出的。

       |--Error錯誤,通常狀況下,不編寫針對性的代碼進行處理,一般是jvm發生的,須要對程序進行修正。

       |--Exception異常,能夠有針對性的處理方式

不管是錯誤仍是異常,它們都有具體的子類體現每個問題,它們的子類都有一個共性,就是都以父類名才做爲子類的後綴名

這個體系中的全部類和對象都具有一個獨有的特色;就是可拋性。

可拋性的體現:就是這個體系中的類和對象均可以被throws和throw兩個關鍵字所操做。

class  ExceptionDemo{
       public static void main(String[] args) {
//            byte[] buf = new byte[1024*1024*700];//java.lang.OutOfMemoryError內存溢出錯誤
       }
}

在開發時,若是定義功能時,發現該功能會出現一些問題,應該將問題在定義功能時標示出來,這樣調用者就能夠在使用這個功能的時候,預先給出處理方式。

3.標示方法:經過throws關鍵字完成,格式:throws 異常類名,異常類名...標示後,調用者在使用該功能時,就必需要處理,不然編譯失敗。

4.處理方式:一、捕捉;二、拋出。

對於捕捉:java有針對性的語句塊進行處理。

try {
   須要被檢測的代碼;
}
catch(異常類 變量名){
   異常處理代碼;
}
fianlly{
   必定會執行的代碼;
}

--------------------------------------------------------

catch (Exception e) { //e用於接收try檢測到的異常對象。
       System.out.println("message:"+e.getMessage());//獲取的是異常的信息。
       System.out.println("toString:"+e.toString());//獲取的是異常的名字+異常的信息。
       e.printStackTrace();//打印異常在堆棧中信息;異常名稱+異常信息+異常的位置。
}

異常處理原則:功能拋出幾個異常,功能調用若是進行try處理,須要與之對應的catch處理代碼塊,這樣的處理有針對性,拋幾個就處理幾個。

特殊狀況:try對應多個catch時,若是有父類的catch語句塊,必定要放在下面。

throw 和throws關鍵字的區別:

throw用於拋出異常對象,後面跟的是異常對象;throw用在函數內。
throws用於拋出異常類,後面跟的異常類名,能夠跟多個,用逗號隔開。throws用在函數上。

一般狀況:函數內容若是有throw,拋出異常對象,並無進行處理,那麼函數上必定要聲明,不然編譯失敗。可是也有特殊狀況。

異常分兩種:

1:編譯時被檢查的異常,只要是Exception及其子類都是編譯時被檢測的異常。
2:運行時異常,其中Exception有一個特殊的子類RuntimeException,以及RuntimeException的子類是運行異常,也就說這個異常是編譯時不被檢查的異常。

編譯時被檢查的異常和運行時異常的區別:

編譯被檢查的異常在函數內被拋出,函數必需要聲明,否編譯失敗。
聲明的緣由:是須要調用者對該異常進行處理。
運行時異常若是在函數內被拋出,在函數上不須要聲明。
不聲明的緣由:不須要調用者處理,運行時異常發生,已經沒法再讓程序繼續運行,因此,不讓調用處理的,直接讓程序中止,由調用者對代碼進行修正。

定義異常處理時,功能內部若是出現異常,若是內部能夠處理,就用try;若是功能內部處理不了,就必須聲明出來,讓調用者處理。

自定義異常:當開發時,項目中出現了java中沒有定義過的問題時,這時就須要咱們按照java異常創建思想,將項目的中的特有問題也進行對象的封裝。這個異常,稱爲自定義異常。

對於除法運算,0做爲除數是不能夠的。java中對這種問題用ArithmeticException類進行描述。對於這個功能,在咱們項目中,除數除了不能夠爲0外,還不能夠爲負數。但是負數的部分java並無針對描述。因此咱們就須要自定義這個異常。

自定義異常的步驟:

1:定義一個子類繼承Exception或RuntimeException,讓該類具有可拋性。

2:經過throw 或者throws進行操做。

異常的轉換思想:當出現的異常是調用者處理不了的,就須要將此異常轉換爲一個調用者能夠處理的異常拋出。

當異常出現後,在子父類進行覆蓋時,有了一些新的特色:

1:當子類覆蓋父類的方法時,若是父類的方法拋出了異常,那麼子類的方法要麼不拋出異常要麼拋出父類異常或者該異常的子類,不能拋出其餘異常。
2:若是父類拋出了多個異常,那麼子類在覆蓋時只能拋出父類的異常的子集。

注意:

若是父類或者接口中的方法沒有拋出過異常,那麼子類是不能夠拋出異常的,若是子類的覆蓋的方法中出現了異常,只能try不能throws。
若是這個異常子類沒法處理,已經影響了子類方法的具體運算,這時能夠在子類方法中,經過throw拋出RuntimeException異常或者其子類,這樣,子類的方法上是不須要throws聲明的。

常見異常:

一、腳標越界異常(IndexOutOfBoundsException)包括數組、字符串;

空指針異常(NullPointerException)

二、類型轉換異常:ClassCastException

三、沒有這個元素異常:NullPointerException

四、不支持操做異常;

異常要儘可能避免,若是避免不了,須要預先給出處理方式。好比家庭備藥,好比滅火器。

chapter9 collection和maps

1.Map集合:

|--Hashtable底層是哈希表數據結構,是線程同步的。不能夠存儲null鍵,null值。

|--HashMap底層是哈希表數據結構,是線程不一樣步的。能夠存儲null鍵,null值。替代了Hashtable.

|--TreeMap底層是二叉樹結構,能夠對map集合中的鍵進行指定順序的排序。

Map集合存儲和Collection有着很大不一樣:

Collection一次存一個元素;Map一次存一對元素。

Collection是單列集合;Map是雙列集合。

Map中的存儲的一對元素:一個是鍵,一個是值,鍵與值之間有對應(映射)關係。

特色:要保證map集合中鍵的惟一性。

1,添加。

put(key,value):當存儲的鍵相同時,新的值會替換老的值,並將老值返回。若是鍵沒有重複,返回null。
void putAll(Map);

2,刪除。

void clear():清空
value remove(key) :刪除指定鍵。

3,判斷。

boolean isEmpty():
boolean containsKey(key):是否包含key
boolean containsValue(value) :是否包含value

4,取出。

int size():返回長度
value get(key) :經過指定鍵獲取對應的值。若是返回null,能夠判斷該鍵不存在。固然有特殊狀況,就是在hashmap集合中,是能夠存儲null鍵null值的。
Collection values():獲取map集合中的全部的值。

5,想要獲取map中的全部元素:

原理:map中是沒有迭代器的,collection具有迭代器,只要將map集合轉成Set集合,可使用迭代器了。之因此轉成set,是由於map集合具有着鍵的惟一性,其實set集合就來自於map,set集合底層其實用的就是map的方法。

把map集合轉成set的方法:

Set keySet();
Set entrySet();//取的是鍵和值的映射關係。

Entry就是Map接口中的內部接口;

爲何要定義在map內部呢?entry是訪問鍵值關係的入口,是map的入口,訪問的是map中的鍵值對。

1.取出map集合中全部元素的方式一:keySet()方法。

能夠將map集合中的鍵都取出存放到set集合中。對set集合進行迭代。迭代完成,再經過get方法對獲取到的鍵進行值的獲取。

Set keySet = map.keySet();
Iterator it = keySet.iterator();
      while(it.hasNext()) {
            Object key = it.next();
            Object value = map.get(key);
            System.out.println(key+":"+value);
       }        

--------------------------------------------------------

2.取出map集合中全部元素的方式二:entrySet()方法。

Set entrySet = map.entrySet();
Iterator it = entrySet.iterator();
              while(it.hasNext()) {
                     Map.Entry  me = (Map.Entry)it.next();
                     System.out.println(me.getKey()+"::::"+me.getValue());
              }

--------------------------------------------------------

使用集合的技巧:

看到Array就是數組結構,有角標,查詢速度很快。
看到link就是鏈表結構:增刪速度快,並且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast();
看到hash就是哈希表,就要想要哈希值,就要想到惟一性,就要想到存入到該結構的中的元素必須覆蓋hashCode,equals方法。
看到tree就是二叉樹,就要想到排序,就想要用到比較。

比較的兩種方式:

一個是Comparable:覆蓋compareTo方法;

一個是Comparator:覆蓋compare方法。

LinkedHashSet,LinkedHashMap:這兩個集合能夠保證哈希表有存入順序和取出順序一致,保證哈希表有序。

集合:當存儲的是一個元素時,就用Collection。當存儲對象之間存在着映射關係時,就使用Map集合。保證惟一,就用Set。不保證惟一,就用List。

------------------------------------------------------------------------------------------------

Collections它的出現給集合操做提供了更多的功能。這個類不須要建立對象,內部提供的都是靜態方法。

靜態方法:

Collections.sort(list);//list集合進行元素的天然順序排序。
Collections.sort(list,new ComparatorByLen());//按指定的比較器方法排序。
class ComparatorByLen implements Comparator<String>{
     public int compare(String s1,String s2){
            int temp = s1.length()-s2.length();
            return temp==0?s1.compareTo(s2):temp;
     }
}
Collections.max(list); //返回list中字典順序最大的元素。
int index = Collections.binarySearch(list,"zz");//二分查找,返回角標。
Collections.reverseOrder();//逆向反轉排序。
Collections.shuffle(list);//隨機對list中的元素進行位置的置換。

將非同步集合轉成同步集合的方法:Collections中的  XXX synchronizedXXX(XXX);

List synchronizedList(list);

Map synchronizedMap(map);

原理:定義一個類,將集合全部的方法加同一把鎖後返回。

Collection 和 Collections的區別:

Collections是個java.util下的類,是針對集合類的一個工具類,提供一系列靜態方法,實現對集合的查找、排序、替換、線程安全化(將非同步的集合轉換成同步的)等操做。
Collection是個java.util下的接口,它是各類集合結構的父接口,繼承於它的接口主要有Set和List,提供了關於集合的一些操做,如插入、刪除、判斷一個元素是否其成員、遍歷等。

chapter10 輸入輸出

IO流:用於處理設備上數據。

流:能夠理解數據的流動,就是一個數據流。IO流最終要以對象來體現,對象都存在IO包中。

流也進行分類:

1:輸入流(讀)和輸出流(寫)。

2:由於處理的數據不一樣,分爲字節流和字符流。

①字節流:處理字節數據的流對象。設備上的數據不管是圖片或者dvd,文字,它們都以二進制存儲的。二進制的最終都是以一個8位爲數據單元進行體現,因此計算機中的最小數據單元就是字節。意味着,字節流能夠處理設備上的全部數據,因此字節流同樣能夠處理字符數據。

②字符流:由於字符每一個國家都不同,因此涉及到了字符編碼問題,那麼GBK編碼的中文用unicode編碼解析是有問題的,因此須要獲取中文字節數據的同時+ 指定的編碼表才能夠解析正確數據。爲了方便於文字的解析,因此將字節流和編碼表封裝成對象,這個對象就是字符流。只要操做字符數據,優先考慮使用字符流體系。

注意:流的操做只有兩種:讀和寫。

流的體系由於功能不一樣,可是有共性內容,不斷抽取,造成繼承體系。該體系一共有四個基類,並且都是抽象類。

字節流:InputStream  OutputStream

字符流:Reader  Writer

在這四個系統中,它們的子類,都有一個共性特色:子類名後綴都是父類名,前綴名都是這個子類的功能名稱。

public static void main(String[] args) throws IOException { //讀、寫都會發生IO異常
            /*
            1:建立一個字符輸出流對象,用於操做文件。該對象一創建,就必須明確數據存儲位置,是一個文件。
            2:對象產生後,會在堆內存中有一個實體,同時也調用了系統底層資源,在指定的位置建立了一個存儲數據的文件。
            3:若是指定位置,出現了同名文件,文件會被覆蓋。
            */
            FileWriter fw = new FileWriter("demo.txt"); // FileNotFoundException
            /*
            調用Writer類中的write方法寫入字符串。字符串並未直接寫入到目的地中,而是寫入到了流中,(實際上是寫入到內存緩衝區中)。怎麼把數據弄到文件中?
            */
            fw.write("abcde");
            fw.flush(); // 刷新緩衝區,將緩衝區中的數據刷到目的地文件中。
            fw.close(); // 關閉流,其實關閉的就是java調用的系統底層資源。在關閉前,會先刷新該流。
}

 

close()和flush()的區別:

flush():將緩衝區的數據刷到目的地中後,流可使用。

close():將緩衝區的數據刷到目的地中後,流就關閉了,該方法主要用於結束調用的底層資源。這個動做必定作。

--------------------------------------------------------------------------------------------------------------------

io異常的處理方式:io必定要寫finally

FileWriter寫入數據的細節:

1:window中的換行符:\r\n兩個符號組成。 linux:\n。

2:續寫數據,只要在構造函數中傳入新的參數true。

3:目錄分割符:window \\  /

 

public static void main(String[] args) {
                        FileWriter fw = null;
                        try {
                                    fw = new FileWriter("demo.txt",true);
                                    fw.write("abcde");
                        }
                        catch (IOException e ){
                                    System.out.println(e.toString()+"....");
                        }
                        finally{
                                    if(fw!=null)
                                                try{
                                                            fw.close();
                                                }
                                                catch (IOException e){                                                           
                                System.out.println("close:"+e.toString()); } } }

FileReader使用Reader體系,讀取一個文本文件中的數據。返回 -1 ,標誌讀到結尾。

import java.io.*;
class  FileReaderDemo {
            public static void main(String[] args) throws IOException {
                        /*
                        建立能夠讀取文本文件的流對象,FileReader讓建立好的流對象和指定的文件相關聯。
                        */
                        FileReader fr = new FileReader("demo.txt");
                        int ch = 0;
                        while((ch = fr.read())!= -1) { //條件是沒有讀到結尾
                                    System.out.println((char)ch); //調用讀取流的read方法,讀取一個字符。
                        }
                        fr.close();
            }
}

讀取數據的第二種方式:第二種方式較爲高效,自定義緩衝區。

import java.io.*;
class FileReaderDemo2 {
            public static void main(String[] args) throws IOException {
                       FileReader fr = new FileReader("demo.txt"); //建立讀取流對象和指定文件關聯。
                        //由於要使用read(char[])方法,將讀取到字符存入數組。因此要建立一個字符數組,通常數組的長度都是1024的整數倍。
                        char[] buf = new char[1024];
                        int len = 0;
                        while(( len=fr.read(buf)) != -1) {
                                    System.out.println(new String(buf,0,len));
                        }
                        fr.close();
            }
}

IO中的使用到了一個設計模式:裝飾設計模式。

裝飾設計模式解決:對一組類進行功能的加強。

包裝:寫一個類(包裝類)對被包裝對象進行包裝;

包裝類和被包裝對象要實現一樣的接口;
包裝類要持有一個被包裝對象;
包裝類在實現接口時,大部分方法是靠調用被包裝對象來實現的,對於須要修改的方法咱們本身實現;

字符流:

Reader用於讀取字符流的抽象類。子類必須實現的方法只有 read(char[], int, int) 和 close()。

     |---BufferedReader從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。 能夠指定緩衝區的大小,或者可以使用默認的大小。大多數狀況下,默認值就足夠大了。

     |---LineNumberReader跟蹤行號的緩衝字符輸入流。此類定義了方法 setLineNumber(int)getLineNumber(),它們可分別用於設置和獲取當前行號。

     |---InputStreamReader是字節流通向字符流的橋樑:它使用指定的 charset 讀取字節並將其解碼爲字符。它使用的字符集能夠由名稱指定或顯式給定,或者能夠接受平臺默認的字符集。

     |---FileReader用來讀取字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩衝區大小都是適當的。要本身指定這些值,能夠先在 FileInputStream 上構造一個 InputStreamReader。

     |---CharArrayReader

     |---StringReader

Writer寫入字符流的抽象類。子類必須實現的方法僅有 write(char[], int, int)、flush() 和 close()。

     |---BufferedWriter將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入。

     |---OutputStreamWriter是字符流通向字節流的橋樑:可以使用指定的 charset 將要寫入流中的字符編碼成字節。它使用的字符集能夠由名稱指定或顯式給定,不然將接受平臺默認的字符集。

     |---FileWriter用來寫入字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩衝區大小都是可接受的。要本身指定這些值,能夠先在 FileOutputStream 上構造一個 OutputStreamWriter。

     |---PrintWriter

     |---CharArrayWriter

     |---StringWriter

字節流:

InputStream是表示字節輸入流的全部類的超類。

     |--- FileInputStream從文件系統中的某個文件中得到輸入字節。哪些文件可用取決於主機環境。FileInputStream 用於讀取諸如圖像數據之類的原始字節流。要讀取字符流,請考慮使用 FileReader。

     |--- FilterInputStream包含其餘一些輸入流,它將這些流用做其基本數據源,它能夠直接傳輸數據或提供一些額外的功能。

     |--- BufferedInputStream該類實現緩衝的輸入流。

     |--- Stream

     |--- ObjectInputStream

     |--- PipedInputStream

OutputStream此抽象類是表示輸出字節流的全部類的超類。

     |--- FileOutputStream文件輸出流是用於將數據寫入 FileFileDescriptor 的輸出流。

     |--- FilterOutputStream此類是過濾輸出流的全部類的超類。

     |--- BufferedOutputStream該類實現緩衝的輸出流。

     |--- PrintStream

     |--- DataOutputStream

     |--- ObjectOutputStream

     |--- PipedOutputStream

緩衝區是提升效率用的:

BufferedWriter是給字符輸出流提升效率用的,那就意味着,緩衝區對象創建時,必需要先有流對象。明確要提升具體的流對象的效率。

       FileWriter fw = new FileWriter("bufdemo.txt");
       BufferedWriter bufw = new BufferedWriter(fw);//讓緩衝區和指定流相關聯。
       for(int x=0; x<4; x++){
              bufw.write(x+"abc");
              bufw.newLine(); //寫入一個換行符,這個換行符能夠依據平臺的不一樣寫入不一樣的換行符。
              bufw.flush();//對緩衝區進行刷新,可讓數據到目的地中。
       }
       bufw.close();//關閉緩衝區,其實就是在關閉具體的流。

BufferedReader

       FileReader fr = new FileReader("bufdemo.txt");
       BufferedReader bufr  = new BufferedReader(fr);
       String line = null;
       while((line=bufr.readLine())!=null){  //readLine方法返回的時候是不帶換行符的。
              System.out.println(line);
       }
       bufr.close();

流對象:其實很簡單,就是讀取和寫入。可是由於功能的不一樣,流的體系中提供N多的對象。那麼開始時,到底該用哪一個對象更爲合適呢?這就須要明確流的操做規律。

流的操做規律:

1,明確源和目的。

數據源:就是須要讀取,可使用兩個體系:InputStream、Reader;
數據匯:就是須要寫入,可使用兩個體系:OutputStream、Writer;

2,操做的數據是不是純文本數據?

            若是是:數據源:Reader

                       數據匯:Writer

            若是不是:數據源:InputStream

                          數據匯:OutputStream

3,雖然肯定了一個體系,可是該體系中有太多的對象,到底用哪一個呢?

明確操做的數據設備。

數據源對應的設備:硬盤(File),內存(數組),鍵盤(System.in)

數據匯對應的設備:硬盤(File),內存(數組),控制檯(System.out)。

4,須要在基本操做上附加其餘功能嗎?好比緩衝。若是須要就進行裝飾。

轉換流特有功能:轉換流能夠將字節轉成字符,緣由在於,將獲取到的字節經過查編碼表獲取到指定對應字符。

轉換流的最強功能就是基於 字節流 + 編碼表 。沒有轉換,沒有字符流。

發現轉換流有一個子類就是操做文件的字符流對象:

InputStreamReader

            |--FileReader

OutputStreamWriter

            |--FileWrier

想要操做文本文件,必需要進行編碼轉換,而編碼轉換動做轉換流都完成了。因此操做文件的流對象只要繼承自轉換流就能夠讀取一個字符了。

可是子類有一個侷限性,就是子類中使用的編碼是固定的,是本機默認的編碼表,對於簡體中文版的系統默認碼錶是GBK

FileReader fr = new FileReader("a.txt");
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"gbk");

以上兩句代碼功能一致,

若是僅僅使用平臺默認碼錶,就使用FileReader fr = new FileReader("a.txt"); //由於簡化。

若是須要制定碼錶,必須用轉換流。

轉換流 = 字節流+編碼表。

轉換流的子類File = 字節流 + 默認編碼表。

凡是操做設備上的文本數據,涉及編碼轉換,必須使用轉換流。

chapter 12 Lambda

這部份內容書上講的很詳細不少代碼能夠用來參照,知識點就不列舉了。另外因爲這個是JDK 8的新特性,我在網上找了其餘一些探究講解,能夠用來參考。

連接以下:

http://developer.51cto.com/art/201404/435591.htm

chapter 14 NIO和NIO2

這部份內容我至今看的不是很懂,只是看了書上內容反覆看了代碼,可是實際上並不能理解多少。網上也能看到一些資料,可是對本身啓發也不是很大= =。還得繼續研讀。

 

總結

這六個章節是我負責來敲代碼和作記錄的部分。因爲自身的基礎和對一些模塊的學習欠缺致使我看起來也很吃力。在寒假扣除掉不少沒法避免的時間後,我只能算是勉勉強強看了下來。可是後面部分對我來講是真正陌生的,看起來理解慢,內容新,難度又大。實在是沒法對本身寒假的學習感到滿意。我以爲這真的須要認真檢討。有的部分看起來反反覆覆看,也沒有什麼真正學到的,真正記在腦子裏的。我想這對於沒有Java基礎的同窗們來講學起來可能要更加困難。所以還須要花更多的時間來精讀這本教材。經過對之前學過部分的Java資料對比,我發現這本教材講的很詳細,也很簡明易懂。有不少代碼能夠藉助理解。這正是我對讀這本書的動力所在。我總感受這本書的講解風格很適合我來學習新的知識。所以,我會在和新同窗們一塊兒學習的過程當中再去鞏固本身的知識。

相關文章
相關標籤/搜索