序列化與打印流

序列化

ObjectOutputStream類

java.io.ObjectOutputStream類毫目,將java對象的原始數(shù)據(jù)類型寫入到文件,實現(xiàn)對象的持久存儲逾一。
構造方法:
public ObjectOutputStream(OutputStream out):創(chuàng)建一個OutputStream的ObjectOutputStream。構造方法代碼如下:

FileOutputStream fileout=new FileOutputStream("employee.txt");
ObjectOutputStream out=new ObjectOutputStream(fileout);
序列化操作
  1. 一個對象想要序列化,必須滿足兩個條件:
  • 該類必須實現(xiàn)java.io.Serializable接口嫩痰,Serializable是一個標記接口,不實現(xiàn)此接口的類將不會使任何狀態(tài)的序列化或反序列化窍箍,會拋出NotSerializableException
  • 該類的所有屬性必須是可序列化的串纺。如果有一個屬性不需要可序列化的,則該屬性 必須注明是瞬態(tài)的椰棘,使用transient關鍵字修飾纺棺。
import java.io.Serializable;

/**
 * 序列化和反序列化的時候,會拋出NotSerializableException沒有序列化異常邪狞。
 * 類通過實現(xiàn) java.io.Serializable 接口以啟用器序列化功能祷蝌,未實現(xiàn)此接口的類將無法使其任何狀態(tài)序列化和反序列化。
 * Serializable也叫標記型接口
 *      要序列化和反序列化的類必須實現(xiàn)Serializable接口帆卓,就會給他添加一個標記
 *      當我們進行序列化和反序列化的時候巨朦,就會檢測這個類上是否有Serializable標記米丘,有的話就可以序列化和反序列化。沒有就會報錯會拋出NotSerializableException異常糊啡。
 */
public class Student implements Serializable {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}




import org.junit.Test;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
 * java.io.ObjectOutputStream extends OutputStream
 * ObjectOutputStream:對象的序列化流
 * 作用:把對象以流的方式寫入到文件中保存
 *
 * 構造方法:
 *      ObjectOutputStream(OutputStream out):創(chuàng)建寫入指定OutputStream的ObjectOutputStream
 *      參數(shù):
 *          OutputStream out:字節(jié)輸出流拄查。
 * 特有的成員方法:
 *      void writeObject(Object obj):將指定的對象寫入ObjectOutputStream
 * 使用步驟:
 *      1.創(chuàng)建ObjectOutputStream對象,構造方法中傳遞字節(jié)輸入流
 *      2.使用ObjectOutputStream對象中的writeObject棚蓄,把對象寫入到文件中
 *      3.釋放資源
 */

public class DemoObjectStream01 {
    @Test
    public void testObjectOutputStream() throws IOException {
        //創(chuàng)建ObjectOutputStream對象靶累,構造方法中傳遞字節(jié)輸入流
        ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("student.txt"));
        //使用ObjectOutputStream對象中的writeObject,把對象寫入到文件中
        objectOutputStream.writeObject(new Student("橙子",20));
        //釋放資源
        objectOutputStream.close();
    }
}

ObjectInputStream類

ObjectInputStream反序列化流癣疟,將之前使用ObjectOutputStream序列化的原始數(shù)據(jù)恢復對象挣柬。
構造方法:
public ObjectInputStream(InputStream in):創(chuàng)建一個指定的InputStream的ObjectInputStream。

反序列化操作1

如果能找到一個對象的class文件睛挚,我們可以進行反序列化操作邪蛔,調用ObjectinputStream讀取對象的方法。

  • public final Object readObject():讀取一個對象
package com.ft.first.objectStream;

import org.junit.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 * java.io.ObjectInputStream extends InputStream
 * ObjectInputStream:對象反序列化流
 * 作用:把文件保存的對象,以流的方式讀取出來使用
 *
 * 構造方法:
 *      ObjectInputStream(InputStream in):創(chuàng)建一個指定InputStream讀取的ObjectInputStream
 *      參數(shù):
 *          InputStream in:字節(jié)輸入流。
 * 特有的方法:
 *      Object readObject():從ObjectInputStream讀取對象
 * 使用步驟:
 *      1.創(chuàng)建ObjectInputStream對象略就,構造方法中傳遞字節(jié)輸入流。
 *      2.使用ObjectInputStream對象的方法readObject讀取保存對象的文件
 *      3.釋放資源
 *      4.使用讀取出來的對象(打印)
 * readObject()聲明拋出了ClassNotFoundException(class文件找不到異常)
 * 當不存在對象的class文件時拋出此異常
 * 反序列化的前期:
 *      1.類必須實現(xiàn)Serializable
 *      2.必須存在類對應的class文件
 */
public class DemoObjectInputStream01 {
    @Test
    public void TestObjectInputStream() throws IOException, ClassNotFoundException {
        //創(chuàng)建ObjectInputStream對象匠抗,構造方法中傳遞字節(jié)輸入流。
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("student.txt"));
        //使用ObjectInputStream對象的方法readObject讀取保存對象的文件
        Object obj=objectInputStream.readObject();
        //釋放資源
        objectInputStream.close();
        //使用讀取出來的對象(打印)
        System.out.println(obj);
        Student student=(Student) obj;
        System.out.println(student.getName());
        System.out.println(student.getAge());

    }
}
關鍵字

static關鍵字:靜態(tài)關鍵字污抬。靜態(tài)優(yōu)先于非靜態(tài)加載到內存中汞贸。被static修飾的成員變量不能被序列化的,序列化的都是對象印机。
transient關鍵字:瞬態(tài)關鍵字矢腻。
指定成員變量不想被序列化可以使用transient和static,transient跟static差不多只是沒有static的含義射赛。

package com.ft.first.objectStream;

import java.io.Serializable;

/**
 * 序列化和反序列化的時候多柑,會拋出NotSerializableException沒有序列化異常。
 * 類通過實現(xiàn) java.io.Serializable 接口以啟用器序列化功能楣责,未實現(xiàn)此接口的類將無法使其任何狀態(tài)序列化和反序列化竣灌。
 * Serializable也叫標記型接口
 *      要序列化和反序列化的類必須實現(xiàn)Serializable接口,就會給他添加一個標記
 *      當我們進行序列化和反序列化的時候秆麸,就會檢測這個類上是否有Serializable標記初嘹,有的話就可以序列化和反序列化。沒有就會報錯會拋出NotSerializableException異常蛔屹。
 *
 * static關鍵字:靜態(tài)關鍵字削樊。靜態(tài)優(yōu)先于非靜態(tài)加載到內存中豁生。被static修飾的成員變量不能被序列化的兔毒,序列化的都是對象漫贞。
 * private static int age;
 * 序列化寫入:
 * objectOutputStream.writeObject(new Student("橙子",20));
 * 反序列化讀取:
 * Object obj=objectInputStream.readObject();
 * 結果為:Student{name='橙子', age=0}
 *
 * transient關鍵字:瞬態(tài)關鍵字育叁。
 * 被transient修飾的成員變量迅脐,不能被序列化
 * private transient int age;
 * 序列化寫入:
 * objectOutputStream.writeObject(new Student("橙子",20));
 * 反序列化讀取:
 * Object obj=objectInputStream.readObject();
 * 結果為:Student{name='橙子', age=0}
 */
public class Student implements Serializable {
    private String name;
    private transient int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}
反序列化操作2

另外豪嗽,當JVM反序列化對象時谴蔑,能找到class文件,但是class文件在序列化對象之后發(fā)生了修改龟梦,那么反序列化操作也會失敗隐锭,拋出一個InvalidClassException異常。發(fā)生這個異常的原因如下:

  • 該類的序列化版本號與從流中讀取的類描述符的版本號不配匹计贰。
  • 該類包含未知數(shù)據(jù)類型钦睡。
  • 該類沒有可訪問的無參數(shù)構造方法
    Serializable接口給需要序列化的類,提供了一個序列版本號躁倒。serialVersionUID該版本號的目的在于驗證序列化的對象和對應類是否版本配匹荞怒。
    問題:
    每次修改類的定義,都會給class文件生成一個新的序列號秧秉。
    解決方案:
    無論是否對類的定義是否進行修改褐桌,都不重新生成新的序列號∠笥可以手動給類添加一個序列號荧嵌。
    格式在Serialzable接口規(guī)定:
    可序列號類可以通過聲明為"serialVersionUID"的字段(該字段必須是靜態(tài)(static)、最終(final)的long型字段)顯示聲明其自己的serialVersionUID砾淌。
public class Student implements Serializable {
    //定義這個類的serialVersionUID=42L;   不會出現(xiàn)序列號沖突
    static final long serialVersionUID=42L;    //常量不能改變


    private String name;
    //private transient int age;
    private int age;

序列化集合

  1. 將存有多個自定義對象的集合序列化操作完丽,保存到list.txt文件中。
  2. 反序列化list.txt拇舀,并遍歷集合逻族,打印對象信息。
案例分析
  1. 把若干個學生對象骄崩,保存到集合中聘鳞。
  2. 把集合序列化。
  3. 反序列化讀取時要拂,只需要讀取一次抠璃,轉換為集合類型。
  4. 遍歷集合脱惰,可以打印所有學生信息搏嗡。
案例實現(xiàn)
import org.junit.Test;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 練習:序列化集合
 * 當我們想在文件中保存多個對象的時候,可以把多個對象存儲到一個集合中,對集合進行序列化和反序列化
 * 分析:
 * 1.定義一個存儲Student對象的ArrayList集合
 * 2.往ArrayList集合中存儲Student對象
 * 3.創(chuàng)建一個序列化流ObjectOutputStream對象
 * 4.使用ObjectOutputStream對象中的方法writeObject采盒,對集合進行序列化
 * 5.創(chuàng)建一個反序列化ObjectInputStream對象
 * 6.使用ObjectInputStream對象中的方法readObject旧乞,讀取文件中保存的集合
 * 7.把Object類型的集合轉換為ArrayList類型
 * 8.遍歷ArrayList集合
 * 9.釋放資源
 */
public class DemoObjectInputStream02 {
    @Test
    public void testListStudent() throws IOException, ClassNotFoundException {
        //定義一個存儲Student對象的ArrayList集合
        List list = new ArrayList();
        //往ArrayList集合中存儲Student對象
        list.add(new Student("張三", 18));
        list.add(new Student("李四", 19));
        list.add(new Student("王五", 20));
        //創(chuàng)建一個序列化流ObjectOutputStream對象
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("listStudent.txt"));
        //使用ObjectOutputStream對象中的方法writeObject,對集合進行序列化
        objectOutputStream.writeObject(list);
        //創(chuàng)建一個反序列化ObjectInputStream對象
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("listStudent.txt"));
        //使用ObjectInputStream對象中的方法readObject磅氨,讀取文件中保存的集合
        Object obj = objectInputStream.readObject();
        //把Object類型的集合轉換為ArrayList類型
        ArrayList<Student> list1=(ArrayList<Student>)obj;
        //遍歷ArrayList集合
        for(Student s:list1){
            System.out.println(s);
        }
        //釋放資源
        objectInputStream.close();
        objectOutputStream.close();
    }
}

打印流

概述

平時我們在控制臺打印輸出尺栖,是調用print方法和println方法完成的,這兩個方法都是來自于java.io.PrintStream類烦租,該類能夠方便地打印各種數(shù)據(jù)類型的值延赌,是一種便捷的輸出方式。
最常見的:

System.out.println(" ");
PrintStream類

構造方法:

  • public PrintStream(String fileName):使用指定的文件名創(chuàng)建一個新的打印流叉橱。

構造舉例挫以,代碼如下:

PrintStream ps=new PrintStream("ps.txt");

改變打印流方向
System.out就是PrintStream類型的,只不過它的流向是系統(tǒng)規(guī)定的窃祝,打印在控制臺上屡贺。不過,既然是流對象锌杀,我們就可以玩一個"小把戲"甩栈,改變它的流向。

import org.junit.Test;

import java.io.FileNotFoundException;
import java.io.PrintStream;

/**
 * java.io.PrintStream:打印流
 * PrintStream 為其他輸出流添加了功能糕再,使他們能夠方便地打印各種數(shù)據(jù)值表示形式量没。
 * PrintStream特點:
 *      1.只負責數(shù)據(jù)的輸出,不負責數(shù)據(jù)的讀取
 *      2.與其他輸出流不同突想,PrintStream永遠不會拋出IOException,但會拋出文件找不到的異常
 *      3.有特有的方法殴蹄,print、println
 *          print:(輸出任意的數(shù)據(jù)格式)
 *          println:(輸出任意的數(shù)據(jù)格式帶換行)
 * 構造方法:
 *      PrintStream(File file):輸出的目的地是文件
 *      PrintStream(OutputStream out):輸出的目的地是一個輸出流
 *      PrintStream(String FileName):輸出的目的地是一個文件路徑
 * PrintStream extends OutputStream
 * 繼承自父類的成員方法:
 *      void close():關閉此輸出流并釋放與此流有關的所有系統(tǒng)資源猾担。
 *      void flush():刷新此輸出流并強制寫出所有緩沖的輸出字節(jié)袭灯。
 *      void write(byte[] b):將 b.length 個字節(jié)從指定的 byte 數(shù)組寫入此輸出流。
 *      void write(byte[] b, int off, int len):將指定 byte 數(shù)組中從偏移量 off 開始的 len 個字節(jié)寫入此輸出流绑嘹。
 *      abstract  void write(int b):將指定的字節(jié)寫入此輸出流稽荧。
 * 注意:
 *      如果使用繼承自父類的write方法寫數(shù)據(jù),那么查詢數(shù)據(jù)的時候會查詢編碼表工腋。例:97->a
 *      如果使用它自己的方法print姨丈、println寫數(shù)據(jù),寫的數(shù)據(jù)會原樣輸出.例:97->97
 */
public class OutStream {
    @Test
    public void testOut() throws FileNotFoundException {
        //創(chuàng)建打印流PrintStream對象擅腰,構造方法中綁定要輸出的目的地
        PrintStream printStream=new PrintStream("print.txt");
        //如果使用繼承自父類的write方法寫數(shù)據(jù)蟋恬,那么查詢數(shù)據(jù)的時候會查詢編碼表。例:97->a
        printStream.write(97);
        //如果使用它自己的方法print趁冈、println寫數(shù)據(jù)歼争,寫的數(shù)據(jù)會原樣輸出.例:97->97
        printStream.println(97);
        //釋放資源
        printStream.close();
    }

    /**
     * 可以改變輸出語句的目的地(打印的流向)
     * 輸出語句拜马,默認在控制臺輸出
     * 使用:System.setOut方法改變輸出語句的目的地改為參數(shù)中傳遞的打印流的目的地。
     *      static void setOut(PrintStream out):重新分配"標準"輸出流沐绒。
     */
    @Test
    public  void testOut01() throws FileNotFoundException {
        System.out.println("我是在控制臺打印輸出");
        PrintStream printStream=new PrintStream("打印流.txt");
        //把輸出語句的目的地改變?yōu)榇蛴×鞯哪康牡?        System.setOut(printStream);
        System.out.println("我在打印流的目的地中輸出");
        printStream.close();
    }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末俩莽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子洒沦,更是在濱河造成了極大的恐慌,老刑警劉巖价淌,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件申眼,死亡現(xiàn)場離奇詭異,居然都是意外死亡蝉衣,警方通過查閱死者的電腦和手機括尸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來病毡,“玉大人濒翻,你說我怎么就攤上這事±材ぃ” “怎么了有送?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長僧家。 經常有香客問我雀摘,道長,這世上最難降的妖魔是什么八拱? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任阵赠,我火速辦了婚禮,結果婚禮上肌稻,老公的妹妹穿的比我還像新娘清蚀。我一直安慰自己,他們只是感情好爹谭,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布枷邪。 她就那樣靜靜地躺著,像睡著了一般诺凡。 火紅的嫁衣襯著肌膚如雪齿风。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天绑洛,我揣著相機與錄音救斑,去河邊找鬼。 笑死真屯,一個胖子當著我的面吹牛脸候,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼运沦,長吁一口氣:“原來是場噩夢啊……” “哼泵额!你這毒婦竟也來了?” 一聲冷哼從身側響起携添,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤嫁盲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后烈掠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羞秤,經...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年左敌,在試婚紗的時候發(fā)現(xiàn)自己被綠了瘾蛋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡矫限,死狀恐怖哺哼,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情叼风,我是刑警寧澤取董,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站无宿,受9級特大地震影響甲葬,放射性物質發(fā)生泄漏。R本人自食惡果不足惜懈贺,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一经窖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧梭灿,春花似錦画侣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至皮迟,卻和暖如春搬泥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伏尼。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工忿檩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爆阶。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓燥透,卻偏偏與公主長得像沙咏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子班套,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內容