Java基礎總結之各個模組重要知識點
一:物件模組。
一.初始化
1.對this.super,建構函式,構造程式碼塊,靜態程式碼塊總結。
this:代表當前物件,也就是所在函式所屬物件的引用。 this物件後面加.呼叫的是物件的成員變數和方法。(this.say()); this物件後面加(),呼叫的是本類中對應引數的建構函式。 super:代表父類,也就是當前類的父類。 使用方式與this類似。 建構函式:用於當對物件初始化時呼叫的特殊函式,只在執行一次。 在建構函式中使用this或者super,必須定義在建構函式的第一行。如果沒有用到,那麼建構函式的第一句會預設的加上super(); 構造程式碼塊:是給所有的物件進行初始化,也就是,所有的物件都會呼叫的一個程式碼塊,只要物件一建,就會呼叫這個程式碼塊,用於給不同物件的共性初始化,優先於建構函式執行。 格式:{ 程式碼。。。。。。 } 靜態程式碼塊:一個用static關鍵字標示的一個程式碼塊區域,定義在類中。可以完成類的初始化,靜態程式碼塊會隨著類的載入而執行一次(new多個物件也是隻執行一次)。如果和主函式在同一個類中,優先於主函式執行。 格式:static{ 程式碼。。。。。 } 三種初始化的執行順序: 靜態程式碼塊--->構造程式碼塊------>建構函式。二.繼承(extends):
1.重寫和過載
重寫:覆蓋父類已有的方法,子父類方法必須一模一樣。(包括返回值,子類複寫父類方法時訪問許可權必須比父類大或者同級。方法要麼都靜態,要麼都不靜態)。 過載:只在本類中的多個方法,只看同名函式的引數列表。 子類初始化時,先初始化父類的方法和變數,在初始化自己的。三.介面(implements)
1.實現
介面可以被多實現,類繼承只能單繼承。 介面與介面之間存在著繼承關係,介面可以多繼承介面。四.多型
體現:父類或者介面的引用指向自己的子類物件。(注意:在使用多型時,要訪問子類的方法,要求父類中必須對該方法進行了宣告或者定義)。
多型在子父類中的成員上的體現的特點:
成員變數: 編譯時期:參考的引用型別變數所屬的類中是否有呼叫的成員。(編譯時期不產生物件,只檢查語法錯誤)。 執行時期:也是參考引用型別變數所屬的類中是否有呼叫的成員。 簡單總結:成員變數——編譯執行都看 = 左邊。 非靜態成員函式: 編譯時期:參考引用型別變數所屬的類中是否有呼叫的方法。 執行時期:參考的是物件所屬的類中是否有呼叫的方法。 原因:因為在子父類的非晶態成員函式中有一個特性:重寫(覆蓋)。 簡單總結:成員函式——編譯看 = 左邊, 執行看 = 右邊。 靜態函式: 編譯時期:參考引用型別變數所屬的類中是否有呼叫的方法。 執行時期:參考的是引用型別所屬的類中是否有呼叫的方法。 原因:因為是靜態方法,所以是不屬於物件的,而是屬於該方法所在的類。 簡單總結:成員函式——編譯執行看 = 左邊,五:內部類。
當內部類定義在外部類的成員變數位置。可以使用一些成員修飾符進行修飾預設,private,static.
1.預設修飾符。
直接訪問內部類格式:外部類名.內部類名 變數名 = new 外部類物件.內部類物件;
Outer.Inner in = new Quter.new Inner();
上面這種方式比較少見,因為內部類本來就是為了封裝,想要獲取內部類物件通常都是通過外部類的方法來獲取,這樣可以對內部類物件進行控制。
2.private修飾符。
通常內部類被封裝,都會被私有化。3.靜態修飾符。
如果內部類被靜態修飾,相當於外部類,會出現訪問侷限性,只能訪問外部類中的靜態成員。注意:如果內部類中定義了靜態成員,那麼該內部類必須是靜態的。
當外部類的靜態方法訪問內部類時,內部類也必須是靜態的。
外部其他類中,直接訪問static內部類的非靜態成員:New Outer.Inner().show();
外部其他類中,直接訪問static內部類的靜態成員:Outer.Inner.show();
一般內部類經過編譯後文件名為:“外部類名$內部類名.class”;
當內部類被定義在區域性位置上時。
1.不可以被成員修飾符修飾(例如:static,static是修飾成員的) 2.可以訪問外部類中成員,因為還持有外部類中的引用,(外部內.this),但不可以訪問它所在的區域性中的變數,只能訪問被final修飾的區域性變數。匿名內部類:
意義:沒有名字的內部類,是內部類的簡化形式,一般內部類只用一次的話就可以用這種形式。匿名內部類其實就是一個匿名子類物件,想要定義匿名內部類:需要前提,內部類必須實現一個介面或者繼承一個類。
匿名內部類的格式:new 父類名&介面名(){定義子類成員或者覆蓋父類方法}.方法 case: new Object(){ void show(){ System.out.prinlt("show run"); } } .show();六:異常。
1.使用throws來在方法上標識(宣告),方法可能會出現異常,當呼叫者檢查到有標識時有必須要進行處理,要麼接著拋,要麼try。否則會出現編譯失敗 宣告格式:throws 異常類,異常類。。。。。並不是所有的異常都需要宣告,RuntimeException(執行時異常)類及其子類可以不用宣告。 2.捕獲異常try{}catch(){}塊來捕捉時,要注意有多個catch時,如果有父類的Exception語句塊,一定要放在下面. 3.throw用於丟擲異常物件。異常,在子父類進行覆蓋時,有以下特點:
1.當子類覆蓋父類的方法時,如果父類的方法丟擲了異常,那麼子類的方法要麼不丟擲異常,要麼就丟擲父類異常或者該異常的子類,不能丟擲其他異常。如果父類沒有丟擲異常,那麼子類只能try不能throws. 2.如果父類丟擲了多個異常,那麼子類在覆蓋時只能丟擲父類異常的子集。 3.如果這個異常子類無法處理,已經影響了子類方法的具體運算,這時可以在子類方法中,通過throw丟擲RuntimeException異常或者其子類,這樣,子類方法就不需要throws進行宣告。注意:throw下面不能寫語句,因為執行不到(會出現編譯錯誤,和return,break後面不能寫程式碼類似),但是注意如果是分支結構,也就是說if語句內寫是可以的。
七:多執行緒。
1.相關概念。
程序:正在進行中的程式,就是一個應用程式執行時的記憶體分配空間 執行緒:程序中一個程式的執行控制單元,一條執行路徑。 程序負責的是應用程式的空間的標示,執行緒負責的是應用程式的執行順序。 cpu隨機性原理:因為cpu的快速切換造成,那個執行緒獲取到了CPU的執行權,那個執行緒就執行。2.執行緒的幾種狀態:
被建立:start()。 執行:具備執行資格,同時具備執行權。 凍結:sleep(time),wait()-----notify()喚醒,執行緒凍結(沉睡),釋放了執行權,同時釋放了執行資格。 臨時阻塞狀態:執行緒具備cpu的執行資格,沒有cpu的執行權。 消亡:stop();3.兩種執行緒的建立方式
第一種方式:繼承Thread,由子類複寫run方法。 步驟:1.定義類繼承Thread類。 2.目的是複寫run方法,將要讓執行緒執行的程式碼都儲存到run方法中。 3.通過建立Thread類的子類物件,建立執行緒物件。 4.呼叫執行緒的start方法,開啟執行緒,並執行run方法。 第二種方式:實現一個Runable介面。 步驟:1.定義類實現Runnable介面。 2.覆蓋介面中的run方法。(用於封裝執行緒要執行的程式碼)。 3.通過Thread類建立執行緒物件。 4.將實現了Runnable介面的子類作為實際引數傳遞給Thread類中的建構函式。(為什麼要這麼做?是為了讓執行緒物件明確要執行的run方法所屬的物件)。 5.呼叫Thread物件的start方法。開啟執行緒,並執行Runnable介面子類中的run方法。 一般情況推薦使用第二種方式,可以避免單繼承。4.執行緒安全問題
通過圖可以發現一個執行緒在執行多條語句時,並運算同一個資料時,在執行過程中,其他執行緒參與進來,並操作了這個資料,那麼會導致錯誤資料產生。 產生的兩個因素:1.多條執行緒在操作共享資料。2.有多條語句對共享資料進行運算。 原因:這多條語句,在某一個時刻被一個執行緒執行是,還沒執行完,cpu時間片到了,被其他執行緒執行了。八:同步(鎖)。
為了解決上面所說的執行緒安全問題而產生的技術,解決的思路就是:加同步,加鎖,將要操作共享資料的語句在某一時段讓一個執行緒執行完,線上程執行過程中,其他執行緒不能進來執行。1.Java中提供了一個解決方式,就是同步程式碼塊。也就是鎖。
格式: synchronized (物件){ //任意物件都可以,這個物件就是鎖 //需要被同步的程式碼 } 定義同步的前提: 1.必須要有兩個或者兩個以上的執行緒,才需要同步。 2.多個執行緒必須保證使用的是同一個鎖。2.另一種表現形式就是同步函式:就是將同步關鍵字定義在函式上,讓函式具備了同步性。
1.同步函式所使用的鎖是this物件。 2.當同步函式被static修飾時,由於此時的函式是屬於類的,這時可能還沒有產生該類的物件,但是該類的位元組碼檔案載入進了記憶體就已經被封裝成了物件,所以此時的鎖就是位元組碼檔案物件,也就是類名.class物件。3.關於同步程式碼塊和同步函式的區別?
同步程式碼塊使用的鎖可以是任意物件。 同步函式使用的鎖是this,靜態同步函式的鎖是該類的位元組碼檔案物件。4.死鎖。多個同步進行巢狀導致,相互等待。
避免死鎖:執行緒通訊→等待喚醒機制,涉及的方法: wait:將同步中的執行緒處理為凍結狀態。釋放了執行權,釋放了資格。同時將執行緒物件儲存到執行緒池中。 notify:喚醒執行緒池中某一個執行緒。 notifyAll:喚醒執行緒池中所有的執行緒。 注意:1.這些方法都需要定義在同步中。2.因為這些方法都必須要標示所屬的鎖。因為A鎖上的wait只能,讓A鎖去喚醒notify。(A.wait()----->A.notify)。 wait和sleep區別:分析這兩個方法。從執行權和鎖角度來分析。 wait:可以指定時間,也可以不指定時間,如果不指定時間,只能由對應的notify或者notifyAll來喚醒。 執行緒會釋放執行權,而且執行緒也會釋放鎖。 sleep:必須指定時間,時間到執行緒自動由凍結狀態轉為執行狀態(或者臨時阻塞狀態)。 執行緒會釋放執行權,但是不會釋放鎖。九:字串,字元容器。
1.關於字串的方法就不過多提了,就簡單的說下這裡容易出錯的幾個概念。
字串特點:字串一旦被初始化,就不可以改變,存放在方法區的常量池中。只要出現了“ ”(雙引號)的資料那麼就是字串物件。關於 這裡簡單說一下關於Java的記憶體分佈:1:暫存器 2:本地方法區 (靜態方法,常量)3:方法區 4:棧(區域性變數) 5:堆(實體,就是物件和陣列)。 2.字元容器:StringBuffer 和 StringBuilder。 StringBuffer特點:1.初始容量為16個字元。 2.可以對字串內容進行修改。 3.可變長度。 4.快取區中可以儲存任意型別的資料。 5.最終需要變成字串。 6.最重要的執行緒安全的。 StringBuilder:與buffer一模一樣,只是它是執行緒不安全的。 總結:多執行緒操作,使用StringBuffer安全。單執行緒使用StringBuilder效率高。十:集合框架:用於儲存資料的容器。
特點: 1.物件封裝資料,物件多了也需要儲存。集合用於儲存物件。 2.物件的個數確定可以使用陣列,但不確定個數怎麼辦,可以使用集合,因為集合時可變長度 集合與陣列的區別: 1.陣列是固定長度:集合可變長度的。 2.陣列可以儲存基本資料型別,也可以儲存引用資料型別。集合只能儲存引用資料型別。 3.陣列儲存的元素必須是同一個資料型別;集合儲存的物件可以是不同資料型別。--< java.util >-- Collection介面:
Collection:
|--List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素可以重複。
|--Set:無序(存入和取出順序有可能不一致),不可以儲存重複元素。必須保證元素唯一性。
--< java.util >-- Iterator介面:
迭代器:是一個介面。作用:用於取集合中的元素。
boolean |
hasNext() 如果仍有元素可以迭代,則返回 true。 |
next() 返回迭代的下一個元素。 |
|
void |
remove() 從迭代器指向的 collection 中移除迭代器返回的最後一個元素(可選操作)。 |
每一個集合都有自己的資料結構,都有特定的取出自己內部元素的方式。為了便於操作所有的容器,取出元素。將容器內部的取出方式按照一個統一的規則向外提供,這個規則就是Iterator介面。
也就說,只要通過該介面就可以取出Collection集合中的元素,至於每一個具體的容器依據自己的資料結構,如何實現的具體取出細節,這個不用關心,這樣就降低了取出元素和具體集合的耦合性。
-< java.util >-- List介面:
List本身是Collection介面的子介面,具備了Collection的所有方法。現在學習List體系特有的共性方法,查閱方法發現List的特有方法都有索引,這是該集合最大的特點。
List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素可以重複。
|--ArrayList:底層的資料結構是陣列,執行緒不同步,ArrayList替代了Vector,查詢元素的速度非常快。
|--LinkedList:底層的資料結構是連結串列,執行緒不同步,增刪元素的速度非常快。
|--Vector:底層的資料結構就是陣列,執行緒同步的,Vector無論查詢和增刪都巨慢。
對於List的遍歷,不僅可以使用Iterator介面,也可以使用下表(索引)來遍歷,list.get(index);--< java.util >-- Set介面:
Set介面中的方法和Collection中方法一致的。Set介面取出方式只有一種,迭代器。
|--HashSet:底層資料結構是雜湊表,執行緒是不同步的。無序,高效;
HashSet集合保證元素唯一性:通過元素的hashCode方法,和equals方法完成的。
當元素的hashCode值相同時,才繼續判斷元素的equals是否為true。
如果為true,那麼視為相同元素,不存。如果為false,那麼儲存。
如果hashCode值不同,那麼不判斷equals,從而提高物件比較的速度。
|--LinkedHashSet:有序,hashset的子類。
|--TreeSet:對Set集合中的元素的進行指定順序的排序。不同步。TreeSet底層的資料結構就是二叉樹。
雜湊表的原理:
1,對物件元素中的關鍵字(物件中的特有資料),進行雜湊演算法的運算,並得出一個具體的演算法值,這個值 稱為雜湊值。
2,雜湊值就是這個元素的位置。
3,如果雜湊值出現衝突,再次判斷這個關鍵字對應的物件是否相同。如果物件相同,就不儲存,因為元素重複。如果物件不同,就儲存,在原來物件的雜湊值基礎 +1順延。
4,儲存雜湊值的結構,我們稱為雜湊表。
5,既然雜湊表是根據雜湊值儲存的,為了提高效率,最好保證物件的關鍵字是唯一的。
這樣可以儘量少的判斷關鍵字對應的物件是否相同,提高了雜湊表的操作效率。
6.在HashSet中儘量不要改變參與運算hashCode值的變數,以防止記憶體洩露。。
對於ArrayList集合,判斷元素是否存在,或者刪元素底層依據都是equals方法。
對於HashSet集合,判斷元素是否存在,或者刪除元素,底層依據的是hashCode方法和equals方法。
TreeSet:
用於對Set集合進行元素的指定順序排序,排序需要依據元素自身具備的比較性。
如果元素不具備比較性,在執行時會發生ClassCastException異常。
所以需要元素實現Comparable介面,強制讓元素具備比較性,複寫compareTo方法。
依據compareTo方法的返回值,確定元素在TreeSet資料結構中的位置。
TreeSet方法保證元素唯一性的方式:就是參考比較方法的結果是否為0,如果return 0,視為兩個物件重複,不存。
注意:在進行比較時,如果判斷元素不唯一,比如,同姓名,同年齡,才視為同一個人。
在判斷時,需要分主要條件和次要條件,當主要條件相同時,再判斷次要條件,按照次要條件排序。
TreeSet集合排序有兩種方式,Comparable和Comparator區別:
1:讓元素自身具備比較性,需要元素物件實現Comparable介面,覆蓋compareTo方法。
2:讓集合自身具備比較性,需要定義一個實現了Comparator介面的比較器,並覆蓋compare方法,並將該類物件作為實際引數傳遞給TreeSet集合的建構函式。
第二種方式較為靈活。
Map集合:
|--Hashtable:底層是雜湊表資料結構,是執行緒同步的。不可以儲存null鍵,null值。
|--HashMap:底層是雜湊表資料結構,是執行緒不同步的。可以儲存null鍵,null值。替代了Hashtable.
|--TreeMap:底層是二叉樹結構,可以對map集合中的鍵進行指定順序的排序。
Map集合儲存和Collection有著很大不同:
Collection一次存一個元素;Map一次存一對元素。
Collection是單列集合;Map是雙列集合。
Map中的儲存的一對元素:一個是鍵,一個是值,鍵與值之間有對應(對映)關係。
特點:要保證map集合中鍵的唯一性。
想要獲取map中的所有元素:
原理:map中是沒有迭代器的,collection具備迭代器,只要將map集合轉成Set集合,可以使用迭代器了。之所以轉成set,是因為map集合具備著鍵的唯一性,其實set集合就來自於map,set集合底層其實用的就是map的方法。
★ 把map集合轉成set的方法:
Set keySet();
Set entrySet();//取的是鍵和值的對映關係。
Entry就是Map介面中的內部介面;
為什麼要定義在map內部呢?entry是訪問鍵值關係的入口,是map的入口,訪問的是map中的鍵值對。
---------------------------------------------------------
取出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);
}
-------------------------------------------------------
取出map集合中所有元素的方式二:entrySet()方法。
Set entrySet = map.entrySet();
Iterator it = entrySet.iterator();
while(it.hasNext()){
Map.Entryme = (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:它的出現給集合操作提供了更多的功能。這個類不需要建立物件,內部提供的都是靜態方法。
Collection 和 Collections的區別:
Collections是個java.util下的類,是針對集合類的一個工具類,提供一系列靜態方法,實現對集合的查詢、排序、替換、執行緒安全化(將非同步的集合轉換成同步的)等操作。
Collection是個java.util下的介面,它是各種集合結構的父介面,繼承於它的介面主要有Set和List,提供了關於集合的一些操作,如插入、刪除、判斷一個元素是否其成員、遍歷等。
Arrays:
用於運算元組物件的工具類,裡面都是靜態方法。
關於集合內部的方法,這裡就不介紹了,API中都有。
十一:IO流:用於處理裝置上的資料。
相關概念:
1.流:可以理解為資料的流動,就是資料流。IO流最終要以物件來體現,物件都存在IO包中。流的操作只要兩種,讀和寫。 2.流也可以進行分類:1.輸入流(讀)和輸出流(寫)。2.因為處理的的資料不同,分為字元流(Reader Writer)和位元組流(InputStream OutputStream)。 位元組流:處理位元組資料的流物件。計算機底層的資料都是二進位制格式位元組,所以位元組流的資料可以是音訊,圖片,文字等計算機中可以儲存的資料。 字元流:為什麼要有字元流?位元組流不是可以操作一切資料?因為字元每個國家都不一樣,所以涉及到了字元編碼問題,像如果我們的使用GBK的編碼,卻按照ISO8859-1去解碼是有問題的,所以需要我們在獲取文字位元組資料的同時+制定的編碼表才可以正確解析資料。因而將位元組流和編碼表封裝為物件,就是字元流,只要操作字元資料,那麼悠閒考慮使用字元流體系。重要知識點:
1.close()方法和flush()的區別: flush():將快取區的資料刷到目的地中後,流可以繼續使用。 close():將緩衝區資料刷到目的地中後,流就關閉了,該方法主要用於結束呼叫的底層資源,這個動作在使用完畢流後一定要做。 2.FileWriter寫入資料的細節: windows中的換行符:\r\n 兩個符號組成。 linux:\n。 在原資料上續寫資料,只要在new 流物件的建構函式中傳入新的引數true。 目錄分割符: windows \\ /。 流的兩種讀取資料方法:1.不帶緩衝區,每次讀取一個(fr.read())。2.自定義緩衝區(fr.read(buff)) case 1:核心程式碼FileReader fr = new FileReader("demo.txt");
int ch = 0;
while((ch=fr.read)!=-1){
System.out,println((cahr)ch);
}
fr.close();
case 2:
FileReader fr = new FileReader("demo.txt")
char[] buff = new char[1024]; //自定義的緩衝區
int len = 0;
while((len=fr.read(buff))!=-1){
System.out.println(buff,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:該類實現緩衝的輸入流。
|--- ObjectInputStream:
|--- PipedInputStream:
-----------------------------------------------
OutputStream:此抽象類是表示輸出位元組流的所有類的超類。
|--- FileOutputStream:檔案輸出流是用於將資料寫入 File 或 FileDescriptor 的輸出流。
|--- 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 = 位元組流 + 預設編碼表。
轉換流使用格式:轉換流 fr = new 轉換流(包裝的流,指定的編碼集); InputStreamReader fr = new InputStreamReaderfr (new FileInputStream("a.txt"),"GBK")十二:網路程式設計。
相關概念:
1.邏輯埠:用於表示程序的邏輯地址,不同的程序的標識;有效程序:0~65535,其中0~1024是系統使用或者保留埠2.物理埠:指的是主機或者其他裝置上提供的外接介面。
Java中的IP物件 InetAddress.
Socket套接字,通訊的端點:就是為網路服務提供的一種機制,通訊兩端都有Socket,網路通訊其實就是埠Socket間的通訊,資料在兩個Socket之間通過IO傳輸
應用層的主要協議和方式有兩張:UDP 和 TCP 兩種.
1.UDP:面向資料包的傳輸,是面向無連線的方式.
UDP傳輸:1.只要進行網路傳輸,必須需要Socket套接字。
2.資料一定要封裝到資料包中,資料包中包含IP地址,埠號,資料等資訊。
Java中封裝操作UDP來進行網路通訊的主要類是DatagramSocket物件以及DatagramPacket(資料包)。
DatagramSocket:具備接受和傳送功能,但進行傳輸時,需要明確傳送端和接收端。
DatagramPacket:資料包物件,用於操作資料包中的各種資訊。
UDP傳輸傳送端的步驟:
1.建立UDP的Socket服務,建立物件時如果沒有宣告埠,那麼系統會自動分配給其一個未使用的埠號。
2.明確要傳送的資料。
3.將資料封裝到資料包物件中。
4.用Socket的Send方法將資料包傳送出去。
5.關閉資源(必須記得做)
下面給出一個例子作為參考:
class UdpSend{
public static void main (String[] args){
//1.使用DatagramSocket來建立UDP的Socket服務
DatagramSocket ds = new DatagramSocket(8088);//指定傳送端的埠8088,如果不指定自動預設分配
//2.明確要傳送的具體資料
String context = "傳送一段UDP資訊。";
byte[] buff = context.getBytes();
//3.將資料封裝到要傳送的資料包中
DatagramPacket dp = new DatapramPacket(buff,buff.length,InetAddress.getName("192.168.0.112"),10000);//要將該資訊發往指定主機的10000埠上
//4.使用Socket的send方法,將資料包傳送出去。
ds.send(dp);
//5.關閉資源
ds.close();
}
}
UDP傳輸接受端的步驟:
1.建立UDP的Socket服務,明確一個埠,作用在於,只有傳送到這個埠的資料才是這個接受端可以接受處理的資料
2.建立資料包物件用於接受(儲存)資料包。
3.利用Socket服務的接受方法將收到的資料儲存到資料包中。
4.通過資料包物件獲取資料包中的具體內容,如ip地址,埠,資料等。
5.關閉資源(必須做)
接受端的例子:
class UdpReceive{
public static void main(String[] args){
//1.使用DatagramSocket建立UDP的Socket服務。
DatagramSocket ds = new DatagramSocket(10000);//設定埠,宣告接受該埠的資料
//2.建立資料包物件,建立接受存收到的資料。(需要先定義位元組陣列,資料包會將接受到的資料存入到位元組陣列中)
byte[] buff = new byte[1024];
DatagramPacket dp = new DatagramPacket(buff,buff.length);
//3.利用Socket服務,接受傳送過來的資料包
ds.receive(dp);//該方法是阻塞式方法,沒有監聽到有資料傳送過來的時候,會一直等待。
//4.通過資料包物件的方法獲取資料包中資訊
String ip = dp.getAddress.getHostAddress();
int port = dp.getPort();
String context = new String(dp.getData(),0,dp.length);
System.out.println("ip:"+ip+" port:"+port+" context:"+context);
//5.關閉資源
ds.close();
}
}
TCP傳輸:兩個端點建立連線後會有一個傳輸資料的通道,這通道成為流,而且是建立在網路基礎之上的流,稱之為Socket流,該流中既有讀取,也有寫入。
相關概念:TCP中的兩個端點需要嚴格區分:一個是服務端,一個是客戶端。
客戶端:對應的物件,Socket
服務端:對應的物件,ServerSocket
TCP客戶端:
1.建立TCPde Socket服務,最好明確具體的地址和埠,這個物件在建立時,就已經可以對指定ip和埠進行連線(三次握手)。
2.如果連線成功,就意味通道建立了,Socket流已經產生了。只要獲取到Socket流中的讀取流和寫入流即可,只要通getInputStream和getOutputStream就可以獲取到兩個流物件。
3關閉資源。
case 1 :
class TcpClient{
public static void main(String[] args){
Socket s = new Socket("192.168.1.112",10002);
OutputStream out = s.getOutputStream(); //獲取了Socket流中的輸出流物件。
out.write("TCP連線。。。".getBytes());
s.close();
}
}
TCP服務端:
1.建立Socket服務,並監聽一個指定的埠。
2.服務端為了客戶端提供服務,獲取客戶端的內容,可以通過accept方法獲取連線過來的客戶端物件。
3.可以通過獲取到的Socket物件中的Socket流和具體的客戶端進行通訊。
4.如果通訊結束,關閉資源。注意:要先關客戶端,再關服務端。
case 2:
class TcpServer{
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10002); //建立服務端的Socket服務
Socket s = ss.accept(); //獲取客戶端物件
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+“.....connection”);
//可以通過獲取到的Socket物件中的Socket流和具體的客戶端進行通訊
InputStream in = s.getInputStream(); //讀取客戶端的資料,使用客戶端物件的Socket讀取流
byte[] buff = new byte[1024];
int len = in,read(buff);
String text = new String(buff,0,len);
System.out.println(text);
//關閉資源,注意一定是先關客戶端,再關閉服務端
s.close();
ss.close();
}
}
網路程式設計中的URLEncoder和URLDecoder.
URLEncoder類的encode()靜態方法:是將一個普通的字串轉化為一個百分號編碼格式字串。
URLDecoder類的decode()靜態方法:是將百分號編碼格式字串轉化為一個普通的字串。
URL與URLConnection物件:前者是表示應用程式和URL之間的通訊連線,後者表示與URL之間的HTTP連線。程式可以通過URLConnection例項向該URL發生請求,讀取URL引用的資源。
未完待續。。。。。持續更新