成鵬致遠 |lcw.cnblog.com|2014-02-01
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接口的作用:開發人員手工實現序列化的操作
使用序列化保存一組對象的時候要使用對象數組的形式操作