JAVA常用類庫
1.StringBuffer
- StringBuffer是使用緩衝區的,本身也是操作字串的,但是與String類不同,String類的內容一旦宣告之後則不可改變,改變的只是其記憶體地址的指向,而StringBuffer中的內容是可以改變的
- 對於StringBuffer而言,本身是一個具體的操作類,所以不能你String那樣採用直接賦值的方式進行物件的例項化,必須通過構造方法完成
- 當一個字串的內容需要被經常改變時就要使用StringBuffer
- StringBuffer的內容是可以修改的,通過引用傳遞的方式完成
- StringBuffer常用方法
- 字串連線操作:append()
- 在任意位置處為StringBuffer新增內容:insert(int offset, boolean b)
- 字串反轉操作:reverse()
- 替換指定範圍的內容:replace(int start, int end, String str)
- 字串擷取:substring(int start, int end)
- 字串擷取:delete(int start, int end)
- 查詢指定的內容是否存在:indexOf()
- 以上的常用方法,實際上對於String類中也是存在的,所以使用的時候直接根據DOC文件檢視即可
- 小結
- 凡是需要頻繁修改字串內容的時候,都要使用StringBuffer類完成
- StringBuffer類中也提供了一些方法是String類中所沒有的,包括:delete()、insert()等等,這些方法需要的時候直接通過DOC文件進行查詢
2.Runtime類
- Runtime:執行時,是一個封裝了 JVM程式的類。每一個JAVA程式實際上都是啟動了一個 JVM程式,那麼每一個JVM程式都是對應這一個Runtime例項,此例項是由 JVM為其例項化的
- Runtime類的定義中根本就沒有構造方法,本類的構造方法被私有化了,通過 getRuntime()靜態方法就可以取得Runtime類的例項
- 得到 JVM資訊:每一個Runtime物件都是由 JVM進行例項化,所以,可以直接通過此類取得一些資訊
- 可以直接使用 Runtime類執行本機的可執行程式:public Process exec(String command) throws IOException
- exec()方法的加值值是 Process,表示一個程式的操作類,可以通過 destroy()方法銷燬掉一個程式
- 小結
- Runtime類本身就是單態設計的一種應用,因為在整個 JVM中只存在一個Runtime類的物件
- 可以使用Runtime類取得 JVM的系統處,或者使用 gc()方法釋放掉垃圾空間
- 還可以使用此類執行本機的程式
3.國際化程式
- 國際化:程式根據不同的語言環境找到不同的資原始檔,之後從資原始檔中取出內容,資原始檔中的內容都是以 key ->value的形式儲存的,所以在讀取的時候通過其 key找到對應的 value即可
- 如果要想實現 Java程式的國際化操作必須通過以下的三個類完成
- java.util.Locale:用於表示一個國家語言類
- java.util.ResourceBundle:用於訪問資原始檔
- java.text.MessageFormat:格式化資原始檔的佔位字串
- Locale類
- Locale表示的是本地,實際上使用的是一個 ISO編碼的封裝類。
- 對於各個國家來說都存在一個唯一的編碼,那麼這種編碼就稱為 ISO編碼,使用Locale可以指定好一個具體的國家編碼
- 中國編碼:zh-CN
- 英語-美國的編碼:eh-US
- 法語的編碼:fr-FR
- ResourceBundle
- 此類是專門完成屬性檔案讀取操作的,讀取的時候直接指定檔名稱即可(此檔名稱一般不需要指定字尾,字尾統一為 *.properties)
- 可以根據Locale所指定的區域碼來自動選擇所需要的資原始檔
- public static final ResourceBundle getBundle(String baseName),此方法就是指定要操作的資原始檔,此方法找到的是預設的作業系統的語言Locale物件
- public final String getString(String key)根據 key取得對應的 value
- 資原始檔命名的時候最好採用單詞首字母大寫的方式完成
- 【注意】對於中文的資原始檔雖然可以直接通中文讀取,但是這樣做是不合理的,應該將其進行 Unicode編碼,轉換為Java認識的16進位制,這樣可以避免一些系統所帶來的亂碼問題,此工具為 JDK自動提供:native2ascii.exe,只要是中文,就必須進行轉碼操作
- 處理動態文字:就必須在資原始檔中進行一些動態文字的配置,設定點位符,則必須使用 MessageForm類,此類是在 java.text包中定義的
- 在 Format類中還存在數字格式化的 Format(NumberFormat)、日期格式化的 Format(DateFormat)
- JAVA新特性:可變引數:在 JDK1.5之後增加了新特性的操作,可以向方法中傳遞可變的引數
- 小結
- 國際化程式實現的思路:程式與顯示相分離,根據不同的 Locale指定的區域找到不同的資原始檔並根據其 key取得對應的 value
- 使用資原始檔的方式儲存所有的資訊內容,其基本原理就是依靠了 ResourceBundle類取得資原始檔中的內容
- MessageForm是 Format類的子類,以後還會有 Format其它子類的講解
4.System類
- System類是一些與系統相關的屬性和方法的集合在 System類中所有的屬性都是靜態的,要想引用這些屬性和方法,直接使用System類呼叫即可
- System類可以通過方法取得一個操作的計算時間:System.currentTimeMillis()
- 還可以列出本機的全部系統屬性:getProperties()
- 一個物件如果不使用,則要等待進行垃圾收集,垃圾收集可以自動呼叫也可以手工呼叫,手工呼叫的時候就是呼叫 System.gc()或者 Runtime.getRuntiom().gc()。但是,如果一個物件在回收之前需要做一些收尾的工作,則就必須覆寫 Object類中的:protected void finalize() throws Throwable,在物件被回收之前進行呼叫,以處理物件回收前的若干操作,例如釋放資源等等
- 只有強制性呼叫 gc()的時候才可以發現物件被回收,當然,如果不呼叫,則系統也會在一定時間內自動進行回收
- 物件生命週期:初始化->物件例項化->垃圾收集->物件終結->解除安裝
- 小結
- System類本身提供的靜態屬性都是與 IO操作有關的,在 IO操作中還將進一步涉及 System類的使用,可以使用 System類取得計算的時間,以及通過 gc()方法進行垃圾收集,此方法就是包裝了 Runtime類中的 gc()方法
5.日期操作類
- Date類是一個較為常用的類,但是其操作的日期格式會有一些不符合於個人的要求,而如果要想進一步取得一些自己需要的時間,則可以使用Calendar類
- 在java.util包中定義了 Date類,Data類本身使用非常簡單,直接輸出其例項化物件即可
- 如果希望可以按照自己需要的格式顯示時間,可以使用 Calendar類,此類可以直接將日期精確到毫秒
- Calendar類是一個抽象類,既然是一個抽象類則肯定無法直接使用,此時就要利用物件多型性的概念,通過向上轉型關係例項化本類物件
- 使用 Calendar類可以非常輕鬆取得一個完整的日期,但是在取得月份的時候要特別注意,需要增加1
- 最好的做法是將 Date進行一些相關的格式化操作
- 小結
- Date類雖然直接取出的時間格式並不是十分理想,但是其作用依然很大
- 通過 Calendar類可以完整的取得時間
6.DateFormat、SimpleDateFormat
- DateFormat類是一個抽象類,其類本身的內部提供了可以直接為其例項化的操作
- 得到日期的 DateFormat物件:public static final DateFormat getDateInstance()
- 得到日期時間的 DateFormat物件:public static final DateFormat getDateTimeInstance()
- 直接使用 DateFormat類完成Date類的轉換:public final String Format(Date date)
- 通過DateFormat類可以直接將 date類的顯示進行合理的格式化操作,此時採用的是預設的格式化操作,也可以通過 Locale物件指定要顯示的區域
- SimpleDateFormat類:功能是完成日期的顯示格式化的
- 要想實現轉換,則必須首先準備好一個模板,通過此模板進行日期資料的提取工作
- 在SimpleDateFormat類使用的時候,必須注意的是構造物件時要傳入匹配的模板
- 構造方法:public SimpleDateFormat(String pattern)
- 轉換:public Date parse(String source) throws ParseException:此時取得的是全部的時間數
- 格式化:public final String format(Date date):將時間重新格式化成字串顯示
- 小結
- DateFormat可以直接使用,但其本身是一個抽象類,可以根據 Locale指定的區域不同得到不同的日期時間顯示效果
- SimpleDateFormat類是 DateFormat類的子類,一般情況下來說 DateFormat類很少會直接使用,而都使用 SimpleDateFormat類完成
- 直接使用 SimpleDateFormat類取得時間會比使用 Calendar類更加方便,而且不用去增加補零的操作,所以在開發中如果需要取得一個日期的話,則基本上都使用 SimpleDateFormat類進行操作
7.Math與Random
- Math類,表示數學操作,Math類中的方法都是靜態方法,直接使用“類.方法名稱()”的形式呼叫即可
- Math.round求四捨五入的時候實際上是將小數點之後的內容全部忽略掉了,如果此時需要進行準確倍數的四捨五入,則需要使用其它的類完成:BigDecimal
- Random類的主要功能是產生隨機數,可以產生一個指定範圍的隨機數,Random類是定義在 java.util包中的類
- 小結
- Math類中的 round()方法要特別注意
- Random類的主要功能
8.NumberFormat
- 可以使用 NumberFormat類進行本地化的數字顯示
- 可以使用 DecimalFormat指定格式化模板
- NumberFormat表示數字的格式化類,即:可以按照本地的風格習慣進行數字的顯示
- MessageForm、DateFormat、NumberFormat是 Format三個常用的子類,如果要想進一步完成一個好的國際化程式,則肯定需要同時使用這樣三個類完成,根據不同的國家顯示日期,或者顯示貨幣的形式
- DecimalFormat是 NumberFormat類的子類,可以直接指定其顯示的模板
- DecimalFormat主要的作用是用來格式化數字使用,當然,在格式化數字的時候要比直接使用 NumberFormat更加方便,因為可以直接指定按使用者自定義的方式進行格式化操作,與之前講解的 SimpleDateFormat類似,如果要想進行自定義格式化操作,則必須指定格式化操作的模板
- 小結
- NumberFormat完成的功能只是根據區域不同固定的數字顯示格式
- DecimalFormat是可以由使用者自己指定其顯示的形式,所以比較好用
9.大數操作
- 在java中有兩個大數的操作類
- 操作整型:BigInteger
- 操作小數:BigDecimal
- 如果在操作的時候一個整型資料已經超過了整數的最大型別長度long的話,則此資料就無法裝入,所以,此時要使用BigInteger類進行操作
- BigDecimal:使用此類可以完成大的小數操作,而且也可以使用此類進行精確的四捨五入,這一點在開發中經常使用
- 對於不需要任何準確計算精度的程式可以直接使用float或double完成,但是如果需要精確計算的結果,則必須使用BigDecimal類
- 小結
- 使用BigDecimal可以指定好四捨五入的精確位置
10.物件克隆技術
- 物件克隆:物件的複製,完整的複製一個物件
- 如果要想完成物件克隆的話,則肯定依靠 Object類:方法:protected Object clone() throws CloneNotSupportedExcetion
- 以上的方法就是物件克隆的方法,如果現在一個類的物件被克隆,則就必須在此類中明確的覆寫此方法,但是此方法不能直接呼叫
- Cloneable是一個介面,但是在此介面中並沒有規定任何的操作方法,所以此介面實際上屬性標識介面,表示一種能力
- 物件克隆支援:在java中支援物件的克隆操作,直接使用 Object類中的clone()方法即可
- 物件所有的類必須實現 Cloneable介面才可以完成物件的克隆操作
- 小結
- 在以後的JAVA類庫中會經常看到 Cloneable介面的出現
- 只有實現了 Cloneable介面的物件才可以被克隆,否則無法克隆
11.比較器(Comparable、Comparator)
- Array類中存在 sort()方法,此方法可以直接對物件進行排序
- 可以直接使用 java.util.Arrays類進行陣列的排序操作,但物件所在的類必須實現 Comparable介面,用於指定排序介面
- 比較器的排序原理:實際上比較器的操作,就是經常聽到的二叉樹的排序演算法
- 排序的基本原理:使用第一個元素作為根節點,之後如果後面的內容比根節點要小,則放在左子樹,如果內容比根節點的內容要大,則放在右子樹
- 另一種比較器:如果一個類已經開發完成,但是此類建立的初期並不實現 Comparable介面,此時肯定是無法進行物件排序操作的,所以為了解決這樣的問題,java又定義了另一個比較器的操作介面:Comparator
- 小結
- 在使用中儘可能還是使用 Comparable在需要排序的類上實現好此介面,而 Comparator需要單獨建立一個排序的類,這樣如果有很多的話,則排序的規則類就會非常的多,操作起來比較麻煩
- 掌握一點:只要是物件排序,則在java中永遠是以 Comparable介面為準
12.觀察者模式
- 如果要想實現觀察者模式,則必須依靠java.util包中提供的 Observable類和 Observer介面
- 在 Observer介面中的 update方法裡面有兩個引數
- o:表示 Observable類的物件
- arg:需要被觀察的內容
- 小結
- 此模式是一種Java本身的機制,不使用 Observer和 Observable也是可以實現的,只是比較複雜
13.正規表示式
- 正規表示式可以方便的對資料進行匹配,可以執行更加複雜的字串驗證,拆分、替換功能
- Pattern、Matcher兩個類為正則的核心操作類,兩個類都定義在 java.util.regex包中
- Pattern類的主要作用是進行正則規範(如“[0-9]”就屬於正則規範)的編寫
- Matcher類主要是執行規範,驗證一個字串是否符合其規範
- 正規表示式
- \d:表示數字,[0-9]
- \D:表示非數字,[^0-9]
- \w:表示字母、數字、下劃線,[a-zA-Z0-9]
- \W:表示非字母、數字、下劃線,[^a-zA-Z0-9]
- 要想驅動正規表示式,必須依靠Pattern類和Matcher類
- Pattern類中沒有明確的構造方法可以供使用者使用,那麼則肯定此類的構造方法被私有化了,則可以直接從Pattern類中取得本類的例項
- 指定好操作的正則:public static Pattern compile(String regex)
- 可以為 matcher類例項化:public Matcher matcher(CharSequence input)
- 拆分:public String[] spilt(Charsequence input)
- 如果要驗證一個字串是否符合規範,則可以使用Matcher類
- 進行字串的驗證:public boolean matcher()
- 字串替換:public String replaceAll(String replacement)
- 只要使用正則的驗證的規則,那麼就可以匹配各種複雜的字串
- String類對正則的支援:在 JDK1.4之後,Java對正則進行了一些擴充,在 String中開始直接支援正則的操作
- 字串匹配:public boolean matchers(String regex)
- 字串替換:public String replaceAll(String regex, String replacement)
- 字串拆分:public String[] split(String regex)
- 【注意】如果有時候發現一個字串無法按照指定的字元拆分的話,則需要使用“\”轉義,轉義的時候兩個“\”表示一個“\”
- 小結
- 使用正則可以方便的完成字串的驗證、拆分、替換等複雜功能
- 在開發中一般都會直接使用 String類中提供好的正則支援,而往往很少直接使用 Pattern類或者Matcher類
- 在一些正則應用的時候,對於一些敏感的字元要進行轉義操作
14.定時排程
- 定時排程:每當一段時間,程式會自動執行,稱為定時排程
- 如果要使用定時排程,則必須保證程式始終執行著才可以,也就是說是相當於定時排程是在程式之外又啟動了一個新的執行緒
- Timer和 TimerTask兩個類完成定時排程
- Timer類
- Timer類是一種執行緒設施,可以用來實現在某一時間或某一段時間後,安排某一個任務執行一次,或定期重複執行
- 該功能要與 TimerTask配合使用。
- TimerTask類用來實現由 Timer安排的一次或重複執行的某一個任務
- 每一個 Timer物件對應的是一個執行緒,因此計時器所執行的任務應該迅速完成,否則可能會延遲後續任務的執行,而這些後續的任務就有可能堆在一起,等到該任務完成後才能快速連續執行
- schedule()與scheduleAtFixedRate()方法的區別
- 兩者的區別在與重複執行任務時,對於時間間隔出現延遲的情況處理
- schedule()方法的執行時間間隔永遠是固定的,如果之前出現了延遲的情況,之後也會繼續按照設定好的間隔時間來執行
- scheduleAtFixedRate()方法可以根據出現的延遲時間自動調整下一次間隔的執行時間
- TimerTask類
- 要想執行具體的任務,則必須使用TimerTask類,TimerTask類是一個抽象類,如果要使用該類,需要自己建立一個類來繼承此類,並實現其中的抽象方法
- 如果現在一個 Timer類要想排程程式的話,則需要使用 TimerTask的子類
- 完成一個具體的任務操作類,以後定時排程的是此類的操作,方法的主體就是 run()方法
- 小結
- 一般在 web的開發中此內容比較有用,因為要維護一個視窗不關閉才可以一直定時操作下去
JAVA IO
1.File類
- 所有的 io操作都儲存在 java.io包中
- 在整個 io包中,唯一表示與檔案本身有關的類就是 File類
- 使用 File類可以進行建立或刪除檔案等常用操作
- 構造方法:public File(String pathname) ->例項化 File類的時候,必須設定好路徑,直接根據路徑找到檔案
- File類常用方法
- 建立檔案:public boolean createNewFile() throws IOException
- 分隔符:File.separator
- 刪除一個檔案:public boolean delete()
- 判斷檔案是否存在:public boolean exists()
- 所有的 JAVA IO操作並不會立刻執行,因為 JAVA是通過 JVM與底層進行互動的,所以所有的操作需要經過 JVM完成,那麼就有可能產生延遲
- 建立資料夾:public boolean mkdir()
- 列出指定目錄的全部檔案
- 以字串陣列的形式返回:public String[] list() ->只是列出全部的名字,包括資料夾名字和檔名字
- 以 File陣列的形式返回:pulic File[] listFiles() ->列出一個完整的路徑,這樣對於程式本身來說是很容易操作的
- 判斷一個給定的路徑是否是目錄:public boolean isDirectory()
- 小結
- File類是在 java.io包中唯一與檔案本身有關的
- 可以使用 File類建立、刪除等常見的檔案操作
- 在使用 File類指定路徑的時候一定要注意作業系統間的差異,儘量使用 separator進行分割
2.RandomAccessFile
- RandomAccessFile類的主要功能是完成隨機讀取功能,可以讀取指定位置的內容
- RandomAccessFile寫資料的時候可以將一個字串寫入,讀的時候需要一個個的以位元組的形式讀取出來
- 如果要想操作檔案內容的話,可以使用 RandomAccessFile完成
- 小結
- RandomAccessFile類的作用
- RandomAccessFile類操作起來比較麻煩,所以在 IO中會提供專門的輸入、輸出操作
3.位元組流與字元流
- 流:在程式中所有的資料都是流的方式進行傳輸或儲存的,程式需要資料的時候要使用輸入流讀取資料,而當程式需要將資料儲存起來的時候,就要使用輸出流完成
- 程式中的輸入輸出都是以流的形式儲存的,流中儲存的實際上全都是位元組檔案
- 在 java.io包中操作檔案內容的主要有兩大類:位元組流、字元流,兩類都分為輸入和輸出操作
- 在位元組流中輸出資料主要是使用 OutputStream完成,輸入使的是 InputStream
- 在字元流中輸出資料主要是使用 Writer類完成,輸入主要是使用 Reader類完成
- 實際上四個操作類都是抽象類
- 在 JAVA中 IO操作也是有相應步驟的,以檔案操作為例,主要的操作流程如下:
- 使用 File類開啟一個檔案
- 通過位元組流或字元流的子類,指定輸出的位置
- 進行讀/寫操作
- 關閉輸入/輸出
- 使用 File類操作的時候一定要有路徑的問題,注意分隔符
- IO操作屬於資源操作,對於資源操作,操作的最後都必須關閉,否則就有可能出現未知的錯誤
- 位元組流
- 位元組流主要是操作 byte型別資料,以 byte陣列為準,主要操作類就是 OutputStream、InputStream
- Byte是位元組,肯定是位元組流操作,所有的資料基本上都可以直接使用 byte陣列表示出來
- OutputStream
- OutputStream是整個 IO包中位元組輸出流的最大父類
- OutputStream是一個抽象類,如果要想使用此類的話,則首先必須子類例項化物件,那麼如果現在要操作的是一個檔案,則可以使用:FileOutputStream類,通過向上轉型之後,可以為 OutputStream例項化
- Closeable:表示可以關閉的操作,因為程式執行到最後肯定要關閉
- Flushable:表示重新整理,清空記憶體中的資料
- InputStream
- 通過 InputStream可以從檔案中把內容讀取進來
- InputStream本身也是一個抽象類,必須依靠其子類,如果現在是從檔案中讀取,子類肯定是 FileInputStream
- 知道檔案大小:直接使用 File類即可:public long length()
- 字元流
- 在程式中一個字元等於2個位元組,JAVA提供了Reader、Writer兩個專門操作字元流的類
- Writer
- Writer本身也是一個抽象類,如果要想使用此類,則肯定要使用其子類,此時如果是向檔案中寫入內容,所以應該使用 FileWriter的子類
- 字元流的操作比位元組流操作好在一點:就是可以直接輸出字串了,不用再像之前那樣進行轉換操作了
- Reader
- Reader是使用字元的方式從檔案之中取出資料
- Reader本身也是抽象類,如果現在要從檔案中讀取內容,則可以直接使用 FileReader子類
- 位元組流與字元流的區別
- 位元組流和字元流使用是非常相似的
- 位元組流在操作的時候本身是不會用到緩衝區(記憶體)的,是與檔案本身直接操作的
- 字元流在操作的時候是使用到緩衝區的
- 【問題】開發中使用位元組流好還是字元流好:在所有的硬碟上儲存檔案或是進行傳輸的時候都是以位元組的方式進行的。包括圖片也是按位元組完成,而字元是隻有在記憶體中才會形成的,所以使用位元組的操作是最多的
- 小結
- 掌握流的概念
- 掌握位元組流和字元流操作檔案的基本步驟
- 本章是以檔案為例,實際以後的所有操作都可以通過此段程式碼完成,只是替換子類而已
- 位元組流和字元流的區別
- 位元組流:沒有使用緩衝區
- 字元流:使用了緩衝區
- 邊讀邊寫的方式在開發中非常有用處
4.位元組-字元轉換流
- 在整個 IO包中,實際上就是分為位元組流和字元流,但是除了這兩個流之外,還存在了一組位元組流-字元流的轉換
- OutputStreamWriter:是Writer的子類,將輸出的字元流變為位元組流,即:將一個字元流的輸出物件變為位元組流的輸出物件
- InputStreamReader:是Reader的子類,將輸入的位元組流變為字元流:即:將一個位元組流的輸入物件變為字元流的輸入物件
- 如果以檔案操作為例
- 則在記憶體中的字元資料需要通過 OutputStreamWriter變為位元組流才能儲存在檔案之中,讀取的時候需要將讀入的位元組流通過 InputStreamReader變為字元流
- 雖然只是以檔案操作為例,因為 OutputStreamWriter中接收的型別是 OutputStream,只要是位元組輸出流都可以使用字元的形式操作
- 而InputStreamReader()中接收的型別是 InputStream,只要是位元組的輸入流都可以使用字元的輸入流操作
- FileWriter和FileReader的說明
- 從 JDK文件中可以知道 FileOutputStream是 OutputStream的直接子類,FileOutputStream也是 InputStream的直接子類
- 但是在字元流檔案的兩個操作類卻有一些特殊
- FileWriter並不直接是Writer的子類,而是 OutputStreamWriter的子類,而 FileReader也是直接是 Reader的子類,是 InputStreamReader的子類
- 那麼從這兩個類的繼承關係就可清楚的發現,不管是使用位元組流還是字元流實際上最終都是以位元組的形式操作輸入輸出流的
- 也就是說:最後不管如何,雖然是以字元的輸出流形式操作了位元組的輸出流,但是實際上還是以位元組的形式輸出,而字元的輸入流,雖然以字元的形式操作,但是實際還是使用的位元組流
- 也就是說:傳輸或者是從檔案讀取資料的時候,檔案裡真正儲存的資料永遠是位元組
- 小結
- 一定要掌握兩個轉換類的作用
- 一定要明白,操作的終端點實際上都是以位元組的形式進行的
- FileWriter和FileReader兩個子類的定義,中間使用了轉換類
5.記憶體操作流
- 之前的輸入和輸出都是從檔案中來的,當然,也可以將輸出的位置設定在記憶體之上
- 此時就要使用 ByteArrayInputStream、ByteArrayOutputStream來完成輸入、輸出功能了
- ByteArrayInputStream:主要完成將內容寫入到記憶體之中
- ByteArrayOutputStream:主要將記憶體中的資料輸出
- 此時操作的時候應該以記憶體為操作點
- 如果要想把一個字元變為小寫,則可以通過包裝類:Character
- 小結
- 記憶體操作流的操作物件一定是以記憶體為準,不要以程式為準
- 實際上此時可以通過向上轉型的關係為 OutputStream或 InputStream例項化
- 這樣的操作可以很好的體現物件的多型性,通過例項化其子類的不同,完成的功能也不同,也就相當於輸出位置也就不同,如果是檔案,則使用 FileXxx,如果是記憶體,則使用 ByteArrayXxx
- 記憶體輸出流是 JAVA開發中也經常要使用到,要重點掌握
6.管道流
- 管道流的主要作用是可以進行兩個執行緒間的通訊,分為管道輸出流(PipedOutputStream)、管道輸入流(PipedInputStream)
- 如果要想進行管道輸出,則必須把輸出流連在輸入流之上,在PipedOutputStream類上有一個方法用於連線管道:public void connect(PipedInputStream snk) throws IOException
- 要想實現管道流,則可以使用 PipedInputStream和 PipedOutputStream
- 小結
- 在 JAVA開發中很少直接去開發多執行緒程式
7.列印流
- 在整個 IO包中,列印流是輸出資訊最方便的類,主要包含位元組列印流(PrintStream)和字元列印流(PrintWriter)
- 在列印流類中定義了很多的 print()或 println()方法,System.out.println(),此方法可以列印任何資料型別
- 構造方法:public PrintStream(OutputStream out) ->引數指定輸出位置
- 在 JDK1.5之後,JAVA又對 PrintStream類進行了擴充,增加了格式化的輸出方式,直接使用 printf()方法就可以完成操作
- 小結
- PrintStream可以方便的完成輸出的功能
- 在以後的輸出中基本上都使用 PrintStream完成,因為比較方便一些
- PrintStream屬於裝飾設計模式
8.System類對 IO類的支援
- System.out和 System.err的區別
- System.out和 System.err都是 PrintStream的例項化物件,而且兩者都可以輸出錯誤資訊,但是一般來講 System.out是將資訊顯示給使用者看,是正常的資訊顯示,而 System.err的資訊正好相反是不希望使用者看到的,會直接在後臺列印,是專門顯示錯誤的
- System.in實際上是一個鍵盤的輸入流,其本身是 InputStream型別的物件,那麼,此時就可以利用此方式完成從鍵盤讀取資料的功能
- 指定了輸入資料的長度,如果現在輸入的資料超過了長度範圍,則只能輸入部分資料
- 指定的 byte陣列長度是奇數的話,則還有可能出現中文亂碼的問題
- 最好的輸入方式
- 最好的輸入方式是將全部輸入的資料暫放到一塊記憶體之中,之後一次性的從記憶體中讀取出資料,這樣所有資料只讀了一次,則不會造成亂碼,而且也不會受長度的限制
- 如果要想實現以上的功能,則只能通過 BufferReader類完成
- 重定向
- 為 System.out輸出重定向:使用 setOut()方法完成
- 為 System.err輸出重定向:使用 setErr()方法完成
- 為 System.in輸出重定向:使用 setIn()方法完成
- 對於重定向操作,基本上都在 System.out上使用,以把資訊展現給使用者觀看
- 小結
- 三個常量的使用
- System.out:是希望使用者可以看見的資訊,用 IDE(Eclipse)的話錯誤資訊是用黑顏色顯示的
- System.err:是不希望使用者可以看見的資訊,用 IDE(Eclipse)的話錯誤資訊是用紅顏色顯示的
- System.in:對應鍵盤輸
- 以上三個常量的輸入、輸出都可以重定向,但是一般只建議修改 setOut的重定向
- System.in 讀取的時候會出現中文亂碼問題,則可以通過 BufferReader完成讀取功能
9.BufferedReader類
- 如果想接收任意長度的資料,而且避免亂碼產生,就可以使用 BufferedReader
- public class BufferedReader extends Reader ->因為輸入的有可能出現中文,所以,此處使用字元流完成
- BufferedReader是從緩衝區中讀取內容,所有的輸入的位元組資料都將放在緩衝區之中
- System.in本身表示的是 InputSteam(位元組流),現在要求接收的是一個字元流,則需要將位元組流變為字元流才可以,InputStreamReader
- 小結
- 掌握 BufferedReader類的作用
- 可以使用 BufferedReader接收輸入的資料
10.Scanner類
- 在 JDK1.5之後 JAVA提供了專門的輸入資料類,此類可以完成 BufferReader類的功能,也可以方便的對輸入資料進行驗證,此類放在 java.util包中,此類是個工具類
- 如果要想輸入空格的話,則就必須修改分隔符,將分隔符變成“\n”
- Scanner這個類雖然可以接收各種型別,但是對於日期型的資料卻無法接收
- 如果要想接收 Date型別的資料,則只能通過字串轉型,但是在接收的時候依然可以使用 Scanner類中提供的方法進行驗證
- 進行驗證:public String next(Pattern pattern)
- 進行接收:public String next(String pattern)
- 還可以直接從檔案中讀取資訊
- 在使用 Scanner讀檔案的時候,要考慮到換行的功能
- 小結
- 掌握 Scanner類的作用:方便的讀取資料
- 在讀取操作的時候一定要注意分隔符的影響
11.資料操作流
- 在 IO包中,提供了兩個與平臺無關的資料操作流
- 資料輸出流:DataOutputStream
- 資料輸入流:DataInputStream
- 通常資料輸出流會按照一定的格式將資料輸出,再通過資料輸入流按照一定的格式將資料讀入
- 如果要想使用資料操作流,則肯定要由使用者自己指定資料的儲存格式,必須按指定好的格式儲存資料,才可以使用資料輸入流將資料讀取出來
- DataOutputStream繼承自 FilterOutputStream類(FilterOutputStream是 OutputStream的子類)同時實現了 DataOutput介面,在 DataOutput介面定義了一系列的寫入各種資料的方法
- DataOutputStream介面定義了一系列的 writeXxx()的操作,可以寫入各種資料型別的資料
- 要想使用 DataOutputStream寫入資料的話,則必須指定好資料的輸出格式
- 小結
- 隨機讀取訪問很相似
- 兩個介面:DataOutput介面、DataInput介面,這兩個介面的操作彼此對應,而且以後還要使用
12.合併流
- 合併流:從概念上講就是內容合併在一起了
- 合併流的主要功能就是將兩個檔案的內容合併成一個檔案
- 主要操作的是內容
- SequenceInputStream類直接繼承自 InputStream
13.壓縮流
- ZIP是一種常見的壓縮形式,在 Java中要想實現 ZIP的壓縮需要匯入 java.util.zip包,可以使用此包中的 ZipFile、ZipOutputStream、ZipInputStream、ZipEntry幾個類完成操作
- 在 JAVA IO中不僅可以實現 ZIP壓縮格式的輸入、輸出,也可以實現 JAR及 GZIP檔案格式的壓縮
- ZipEntry:在每一個壓縮檔案中都會存在多個子檔案,那麼這每一個的子檔案在 JAVA中就使用 ZipEntry表示
- 在例項化 ZipEntry的時候,要設定名稱,此名稱實際上就是壓縮檔案中每一個元素的名稱
- 如果要想完成一個檔案或資料夾的壓縮,要使用 ZipOutputStream類完成,ZipOutputStream是 OutputStream的子類,就是一個位元組的輸出流,此類的功能就是 ZIP格式輸出的
- 在壓縮檔案中,每一個壓縮的內容都可以用一個 ZipEntry表示,所以在進行壓縮之前必須通過 puNextEntry設定一個 ZipEntry即可
- ZipFile:是一個專門表示壓縮檔案的類
- 在 Java中,每一個壓縮檔案都可以使用 ZipFile表示,還可以使用 ZipFile根據壓縮後的檔名稱找到每一個壓縮檔案中的 ZipEntry並將其進行解壓縮操作
- ZipFile在例項化的時候必須接收 File類的例項,此 File類的例項是指向一個壓縮的 *.zip檔案
- ZipEntry物件,可以找到每一個 ZipEntry的輸入流,但是 ZipInputStream並不能得到每一個輸入流,所以需要使用 ZipFile,但是 ZipInputStream在取得每一個 ZipEntry的時候,不需要每一個 ZipEntry的名稱
- 小結
- 壓縮檔案中每一個壓縮實體都使用 ZipEntry儲存,一個壓縮檔案中可能包含一個或多個的 ZipEntry物件
- 在 JAVA中可以進行zip/jar/gz三種格式的壓縮支援,操作流程基本是一樣的
- ZipOutputStream可以進行壓縮的輸出,但是輸出的位置不一定是檔案
- ZipFile表示每一個壓縮檔案,可以得到每一個壓縮實體的輸入流
14.回退流
- 回退:給了使用者第二次讀的機會
- 在 JAVA IO中所有的資料都是採用順序的讀取方式,即,對於一個輸入流來講都是採用從頭到尾順序讀取的,如果在輸入流中某個不需要的內容被讀取進來,則只能通過程式將這些不需要的內容處理掉,為了解決這樣的讀取問題,在 Java中提供了一種回退輸入流(PusbackInputStream、PushbackReader)可以把讀取進來的某些資料重新退回到輸入流的緩衝區中
- 使用 InputStream要使用 read()方法不斷讀取,是採用順序的讀取方式
- 回退操作同樣分為位元組和字元流
- 對於回退操作來說,提供了三個 unread()的操作方法,這三個操作方法與 InputStream類中的 read()方法是一一對應的
15.字元編碼
- 在計算機世界裡,任何的文字都是以指定的 編碼方式存在的,在 JAVA程式的開發中最常見的是以下的幾種:、GBK/GB2312、unicode、UTF
- ISO8859-1:編碼屬於單位元組編碼,最多隻能表示 0~255的字元範圍,主要在英文上應用
- GBK/GB2312:中文的國標編碼,專門用來表示漢字,是雙位元組編碼,GBK包括中文繁體,字型檔更大
- unicode:java中就是使用此編碼式,也是最標準的一種編碼,是使用16進製表示的編碼,但此編碼不相容ISO8859-1編碼
- UTF:由於 nnicode不支援 ISO8859-1編碼,而且容易佔用更多的空間,而且對於英文字母也需要使用兩個位元組編碼,這樣使用 unicode不便於傳輸和儲存,因此產生了 utf編碼,utf編碼相容了 ISO8859-1編碼,同時也可以用來表示所有的語言字元,不過 utf編碼是不定長編碼,每一個字元的長度從 1~6個位元組不等,一般在中文網頁中使用此編碼,因為這樣可以節省空間
- 如果沒有處理好編碼的事情,則肯定在程式中出現亂碼
- 亂碼產生的根本原因就是字元編碼不統一造成的
- 小結
- 瞭解幾種常用的編碼特點
- 理解亂碼是如何產生的
16.物件序列化
- 什麼叫物件序列化:一個物件產生之後實際上是在記憶體中為其開闢了一個儲存空間,方便儲存資訊
- 物件序列化:就是把一個物件變為二進位制的資料流的一種方法,通過物件序列化可以方便的實現物件的傳輸或儲存
- 如果一個類的物件想被序列化,則物件所在的類必須實現 java.io.Serializable介面
- Serializable介面中沒有一個方法,此介面屬於一個標識介面,表示具備了某種能力
- 被序列化了的物件,變為二進位制 byte流
- 物件的序列化和反序列化
- 要想完成的輸入或輸出,還必須依靠物件輸出流(ObjectOutputStream)和物件輸入流(ObjectInputStream)
- 使用物件輸出流輸出序列化物件的步驟,有時也稱為序列化,而使用物件輸入讀入物件的過程,有時也稱為反序列化
- 物件序列化依靠:ObjectOutputStream,物件反序列化依靠:ObjectInputStream
- ObjectOutputStream類的使用形式與 PrintStream非常的相似,在例項化時也需要傳入一個 OutputStream的子類物件,之後根據傳和的 OutputStream子類的物件不同,輸出的位置也不同(裝飾模式)
- SerialVersionUID:在物件進行序列化或反序列化操作的時候,要考慮 JDK版本的問題,如果序列化的 JDK版本和反序列化的 JDK版本不統一則就有可能造成異常,所以在序列化操作中引入了一個 SerialVersionUID的常量,可以通過此常量來驗證版本的一致性,在進行反序列化時,JVM會把傳來的位元組流中的 SerialVersionUID與本地相應實體(類)的 SerialVersionUID進行比較,如果相同就認為是一致的,要以進行反序列化,否則就會出現序列化版本不一致的異常
- 【問題】物件序列化到底序列化了哪些東西:所有的物件擁有各自的屬性值,但是所有的方法都是公共的,所以序列化物件的時候實際上序列化的就是屬性
- Externalizable介面
- 使用Serializable介面可以方便的序列化一個物件,但是在序列化操作中也提供了另外一種序列化機制:Externalizable介面
- 被 Serializable介面宣告的類其物件的內容都將被序列化,如果現在使用者希望可以自己指定序列化的內容,則可以讓一個類實現 Externalizable介面
- 寫入方法:void writeExternal(ObjectOutput put) throws IOException
- 讀取方法:void readExternal(ObjectInput in) throws IOExcetion,ClassNotFoundExceteption
- 在使用 Externalizable介面的時候需要在被序列化的類中定義一個無參建構函式,因為此介面在進行反序列化的時候,會先用類中的無參構造方法為其進行例項化,之後再將內容分別設定到屬性之中
- transient關鍵字:當使用 Serializable介面實現序列化操作時,如果一個物件中的某個屬性不希望被序列化的話,則可以使用 transient關鍵字進行宣告
- transient + Serializable介面完成可以取代 Externalizable介面的功能
- 序列化一組物件
- 物件輸出時只提供了一個物件的輸出操作(writeObject(Object obj)),並沒有提供多個物件的輸出,所以如果現在要同時序列化多個物件的時候就可以使用物件陣列進行操作,因為陣列屬於引用資料型別,所以可以直接使用 Object型別進行接收
- 如果要儲存多個物件,則最好使用物件陣列的形式完成
- 陣列儲存的資料有限,所以為了解決這樣的問題,Java中引入了類集框架解決陣列的儲存限制問題
- 小結
- 物件序列化的作用:物件序列化並不一定都向檔案中儲存,也有可能面向於其它的輸入或輸出
- 被序列化的類必須實現 Serializable介面,如果某個屬性不希望被儲存下來,則可以使用 transient關鍵字宣告
- ObjectOutputStream序列化物件,ObjectInputStream反序列化物件
- Externalizable介面的作用:開發人員手工實現序列化的操作
- 使用序列化儲存一組物件的時候要使用物件陣列的形式操作