1. 程式人生 > >java基礎——3——泛型+異常+IO

java基礎——3——泛型+異常+IO

在Java釋出的JDK1.5版本中增加了泛型支援,所謂的泛型就是為了讓集合在很大程度上記住元素的資料型別。在沒有使用泛型之前,一旦把物件存放進Java集合中,集合只會將元素作為Object物件進行處理。當從集合中取出物件時就需要進行強制型別轉換。如果轉換錯誤,則將會引起ClassCastException異常(型別轉換異常)。
增加泛型支援後的集合,則可以讓集合記住元素的型別,並在編譯時檢查集合中元素的型別,如果往集合中新增不滿足型別要求的物件,編譯器則會提示錯誤。增加泛型後的集合,可以讓程式碼更加簡潔,程式更加健壯。
所謂的泛型就是允許在定義類、介面、方法時使用型別形參,這個型別形參將在宣告變數、建立物件、呼叫方法時動態的指定。
在程式中我們為一個ArrayList<String>

指定了泛型後,可以把這個ArrayList<String>看成ArrayList的子類,這個類只能儲存String型別的元素,但是實際上,系統並沒有為ArrayList<String>生成新的class檔案,也不會把ArrayList<String>當成新類,因為並不存在這種泛型類。
為了表示各種泛型List的父類,可以使用型別萬用字元,型別萬用字元是一個問號?,將一個問號作為型別實參傳給List集合,語法格式為:List<?>。這個問號被稱為萬用字元,它的元素型別可以匹配任何型別。
Java的異常機制主要依賴於try、catch、finally、throw和throws五個關鍵字,其中try關鍵字後面緊跟著一個花括號括起來的程式碼塊,它裡面放置可能會引發異常的程式碼塊。catch後面對應異常型別和一個程式碼塊,用於表明該catch塊用於處理這種型別的程式碼塊,多個catch塊後面還可以跟一個finally塊,用於回收在try塊裡開啟的物理資源,異常機制會保證finally塊總會被執行。throws關鍵字主要在方法簽名中使用,用於宣告該方法可能丟擲的異常;而throw用於丟擲一個實際的異常,throw可以單獨作為語句使用,丟擲一個具體的異常物件。
File是java.io包下代表與平臺無關的檔案和目錄,則程式中操作檔案和目錄,都可以通過File類來完成。File能新建、刪除、重新命名檔案和目錄。File不能訪問檔案內容本身,如果訪問檔案內容本身,則需要使用輸入/輸出流。
File類可以使用檔案路徑字串來建立File例項,該檔案路徑字串既可以是絕對路徑,也可以是相對路徑。在預設情況下,系統總是依據使用者的工作路徑來解釋相對路徑。
建立File物件後,可以呼叫File物件的方法來訪問。常用的方法如下:
1、訪問檔名相關的方法
String getName():返回此檔案物件所表示的檔名或路徑名。
String getPath():返回此File物件所對應的路徑名。
File getAbsoluteFile():返回此File物件所對應的絕對路徑指向的File物件。
String getAbsolutePath():返回此File物件所對應的絕對路徑。
String getParent():返回此File物件所對應的目錄的父目錄,以工作路徑為準,如果已經在工作路徑的根目錄下,則返回null,否則返回父目錄。
boolean renameTo(File newName):重新命名此File物件所對應的檔案或目錄,成功返回true,否則返回false。
2、檔案檢測相關的方法
boolean exists():判斷File物件所對應的檔案或目錄是否存在。
boolean canWrite():判斷File物件所對應的檔案和目錄是否可寫。
boolean canRead():判斷File物件所對應的檔案和目錄是否可讀。
boolean isFile():判斷File物件所對應的是否是檔案。
boolean isDirectory():判斷File物件所對應的是否是目錄。
boolean isAbsolute():判斷File物件所對應的檔案或目錄是否絕對路徑。例如:如果在Unix/Linux等系統上,如果路徑名的開頭是/,則表明File物件對應一個絕對路徑,在Windows等系統上,如果路徑開頭是碟符,則說明它是一個絕對路徑。
3、獲取常規檔案資訊
long lastModified():返回檔案的最後修改時間。
long length():返回檔案內容的長度。
4、檔案操作相關的方法
boolean createNewFile():當此File物件對應的檔案不存在時,建立一個該File物件所對應的檔案,建立成功返回true,否則返回false。
boolean delete():刪除File物件所在的檔案或路徑。
5、目錄操作相關的方法
boolean mkdir():建立一個File物件所對應的目錄,建立的是目錄而不是檔案。
boolean mkdirs():建立一個File物件所對應的所有目錄,如果上級目錄不存在,會同時將上級目錄創建出來。
File[] listFile():列出File物件的所有子檔案和路徑,返回File陣列。
Static File[] listRoots():列出系統所有根路徑。
1、輸入流和輸出流

按照流向來分,可以分為輸入流和輸出流
輸入流:只能從中讀取資料,而不能向其寫入資料;基本上是從磁碟檔案到系統記憶體。
輸出流:只能向其寫入資料,而不能從中讀取資料;基本上是從系統記憶體到磁碟檔案。
Java的輸入流主要由InputStream和Reader作為基類,而輸出流則主要由OutputStream和Writer作為基類。他們都是一些抽象基類,能直接建立例項物件。
2、位元組流與字元流
位元組流和字元流的用法幾乎一樣,區別在於位元組流和字元流所操作的資料單元不同,位元組流操作的資料單元是8位的位元組,而字元流操作的資料單元是16位的字元。
位元組流主要由InputStream
OutputStream作為基類,字元流主要由Reader和Writer作為基類。
InputStream裡包含如下方法:
int read():從輸入流中讀取單個位元組,返回所讀取的位元組資料。
int read(byte[] b):從輸入流中最多讀取b.length個位元組的資料,並將其儲存在位元組陣列b中,返回實際讀取的位元組數。
int read(byte[] b,int off,int len):從輸入流中最多讀取len個位元組的資料,並將其儲存在陣列b中,放入陣列b中時,並不是從陣列起點開始,而是從off位置開始,返回實際讀取的位元組數。
Reader裡包含如下方法:
int read():從輸入流中讀取單個字元,返回所讀取的字元資料
int read(char[] ch):從輸入流中最多讀取ch.length個字元的資料,並將其儲存在字元陣列ch中,返回實際讀取的字元數。
int read(char[] ch,int off,int len):從輸入流中最多讀取len個字元的資料,並將其儲存在字元陣列ch中,放入陣列時,從陣列的off位置開始,返回實際讀取的字元數。
OutputStreamWriter也非常相似,兩個流都提供瞭如下方法進行輸出:
void write(int c):將指定的位元組/字元輸出到輸出流中,其中c既可以表示位元組也可以表示字元。
void write(byte[]/char[] buf):將位元組陣列/字元陣列中的資料輸出到指定輸出流中。
void write(byte[]/char[] buf,int off,int len):將位元組陣列/字元陣列中從off位置開始,長度為len的位元組/字元輸出到輸出流中。
因為字元流直接以字元作為操作單位,所有Writer可以用字串來代替字元陣列,即以String物件作為引數。Writer裡還包含了如下兩個方法。
void write(String str):將str字串裡包含的字元輸出到指定輸出流中。
void write(String str,int off,int len):將字串從off位置開始,長度為len的字元輸出到指定輸出流中。
輸入/輸出體系中提供了兩個轉換流InputStreamReaderOutputStreamWriter,這兩個轉換流用於實現將位元組流轉換成字元流,其中InputStreamReader將位元組輸入流轉換成字元輸入流,OutputStreamWriter將位元組輸出流轉換成字元輸出流.
BufferedReader和java.io.BufferedWriter類各擁有8192字元的緩衝區。當BufferedReader在讀取文字檔案時,會先儘量從檔案中讀入字元資料並置入緩衝區,而之後若使用read()方法,會先從緩衝區中進行讀取。如果緩衝區資料不足,才會再從檔案中讀取,使用BufferedWriter時,寫入的資料並不會先輸出到目的地,而是先儲存至緩衝區中。如果緩衝區中的資料滿了,才會一次對目的地進行寫出。如果要在緩衝區中資料未滿的情況下將資料寫入到目的地,需要使用flush()方法,將資料重新整理一下。
PrintStream和PrintWriter
PrintWriter是與位元組流相對應的字元流。PrintWriter用於大多數輸出,比PrintStream更為合適。建議新開發的程式碼使用PrintWriter類。 PrintWriter類與PrintStream類的方法是對應的。
ByteArrayInputStream和ByteArrayOutputStream為記憶體流或者稱為陣列流。
ByteArrayInputStream 包含一個內部緩衝區,該緩衝區包含從流中讀取的位元組。內部計數器跟蹤read()方法要提供的下一個位元組。ByteArrayOutputStream類實現了一個輸出流,其中的資料被寫入一個 byte 陣列。緩衝區會隨著資料的不斷寫入而自動增長。可使用 toByteArray() 和 toString() 獲取資料。
ByteArrayInputStream和ByteArrayOutputStream,用於以IO流的方式來完成對位元組陣列內容的讀寫,來支援類似記憶體虛擬檔案或者記憶體對映檔案的功能。
DataInputStream和DataOutputStream資料流,用來處理基本資料的IO流。

public static void main(String[] args) throws Exception {
        //建立一個位元組流或者記憶體流,將內容寫入到這個流中
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //Date資料流寫入的內容被儲存在記憶體流baos中
        DataOutputStream dos = new DataOutputStream(baos);
        dos.writeFloat(13.5f);
        dos.writeDouble(12.50);
        dos.writeFloat(14.6f);
        //寫完之後可以將baos流包裝好進行傳輸

        //客戶端接收到伺服器端返回的位元組流,進行一次接收,然後進行處理
        DataInputStream dis = new DataInputStream(new ByteArrayInputStream(baos.toByteArray()));
        //讀取位元組流的時候,必須按照寫入的方式進行讀取,例如:第一個寫入了float資料,那麼讀取的時
//候必須先讀取Float,第二寫入的是Double,那麼讀取第二資料的時候必須讀入Double。
        System.out.println(dis.readFloat());
        System.out.println(dis.readDouble());
        System.out.println(dis.readFloat());
    }

Object物件流
物件序列化:物件序列化可以將物件儲存在磁碟中,或者將物件在網路中進行傳輸。序列化的機制是可以將物件脫離程式的執行而獨立存在。如果讓一個類的物件支援序列化機制,則需要讓這個類實現Serializable介面就可以了。該介面無須實現任何方法,它只是表明該類的例項是可序列化的。
使用物件流ObjectInputStream和ObjectOutputStream將物件儲存到磁碟上或者通過網路進行傳輸。

public static void main(String[] args) throws Exception {
        //建立一個person物件,此物件已經支援序列化
        Person  person = new Person();
        person.setAge(25);
        person.setName("張三");
        //建立一個Object物件輸出流,將此物件寫入到檔案中去
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("./abc/person.txt")));
        oos.writeObject(person);
        oos.close();
        //建立一個Object物件輸入流,將物件從檔案中讀取出來
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("./abc/person.txt")));
        Person ps = (Person)ois.readObject();
        System.out.println(ps.getName());
        System.out.println(ps.getAge());
    }
舉例2:將物件寫入到記憶體流中
    public static void main(String[] args) throws Exception {
        //建立一個person物件,此物件已經支援序列化
        Person  person = new Person();
        person.setAge(25);
        person.setName("張三");
        //建立一個Object物件輸出流,將此物件寫入到記憶體流中去
        ByteArrayOutputStream baos =new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(person);

        //建立一個記憶體輸入流,將物件從記憶體輸出流中獲取出來
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        //建立一個Object物件輸入流,將物件從記憶體輸入中讀取出來
        ObjectInputStream ois = new ObjectInputStream(bais);
        Person ps = (Person)ois.readObject();
        System.out.println(ps.getName());
        System.out.println(ps.getAge());
    }