中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何從Java IO源碼看裝飾者模式的用法

發布時間:2021-11-24 15:21:17 來源:億速云 閱讀:137 作者:iii 欄目:大數據

這篇文章主要講解了“如何從Java IO源碼看裝飾者模式的用法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何從Java IO源碼看裝飾者模式的用法”吧!

前言

設計模式(design pattern)是對軟件設計中普遍存在(反復出現)的各種問題,所提出的解決方案。

我們在做業務開發的時候,要對業務進行抽象,抽象就是在理解了業務之后再給出一個定義,一個概念。所以概念是從實際場景反推出來的,而不是先有概念。設計模式既然是對問題的總結,自然符合先有場景再有概念。

要理解設計模式就要到具體的場景中去,事實證明,網上流傳的諸多書籍或文章舉出的例子,都很勉強。

眾所周期,Java IO體系使用了裝飾者模式,如果不理解這個模式,就很難熟練的使用io相關的API,不如直接到最經典的例子中去,直接看Java io源碼設計,既能理解模式的使用方式,又能熟悉Java IO的用法和體系!

JavaIO源碼示例

    public static void main(String[] args) throws IOException {
        File file = new File("file.txt");//文件內容為:abcdefgh
        InputStream in =
                new BufferedInputStream(
                        new FileInputStream(file), 512);
        int firstByte = in.read();
        System.out.println(firstByte);
        int secondByte = in.read();
        System.out.println(secondByte);
    }
   //輸出結果:97,98

這段代碼的意思是:使用FileInputStream從文件中讀取數據,使用BufferedInputStream包裝數據,并且分配一個512字節大小的緩沖區。使用 in.read()讀取一個字節的數據。當讀取第一個字節的時候,因為緩沖區沒有內容,所以會調用FileInputStream從文件中讀取512個字節放入內存緩沖區,當讀取第二個字節的時候,因為緩存區已經有數據,所以直接返回。如果不使用BufferedInputStream,則每次都要到文件中讀取一個字節,效率低,這就是使用BufferedInputStream做緩沖的意義。

這里為什么輸出97?文件中使用utf-8編碼,使用不定長的1-4個字節來表示一個字符,對于ascii里面的字符只使用一個字節,所以文件中第一個字節即字符a的utf-8的編碼,也等于ascii編碼,換算成十進制即97。

下面是BufferedInputStream的構造方法:

public BufferedInputStream(InputStream in, int size) {
    super(in);
    if (size <= 0) {
        throw new IllegalArgumentException("Buffer size <= 0");
    }
    buf = new byte[size];
}

下面是BufferedInputStream的read方法:這里判斷pos與count的比較,count是緩沖區中的有效字節數,pos即當前讀取位置,構造方法只是初始化一個字節數組,里面還沒有有效數據,所以第一次讀取時count為0,pos為0,這時候調用fill方法填充緩存區數據。

public synchronized int read() throws IOException {
    if (pos >= count) {
        fill();
        if (pos >= count)
            return -1;
    }
    return getBufIfOpen()[pos++] & 0xff;
}

下面是BufferedInputStream的fill方法,刪減一部分不必要的內容,這里的buffer就是初始化的緩沖區,其調用了getInIfOpen方法將數據寫入緩沖區。

private void fill() throws IOException {
    byte[] buffer = getBufIfOpen();
    count = pos;
    int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
    if (n > 0)
        count = n + pos;
}

getInIfOpen方法使用in這個對象,這個in即構造方法傳入的FileInputStream,所以就相當于調用FileInputStream讀取512字節的數據寫入到BufferedInputStream的緩沖區。

private InputStream getInIfOpen() throws IOException {
    InputStream input = in;
    if (input == null)
        throw new IOException("Stream closed");
    return input;
}

可以看到BufferedInputStream起到的是一個提供緩沖區的增強功能。那么還有沒有別的增強功能?

    public static void main(String[] args) throws IOException {
        File file = new File("file.txt");//文件內容:abcde
        DataInputStream in =
                new DataInputStream(new BufferedInputStream(
                        new FileInputStream(file), 512));
        char c = in.readChar();
        System.out.println(c);
    }//輸出結果:慢

這里使用DataInputStream繼續包裝BufferedInputStreamDataInputStream從基礎輸入流中讀取原始Java數據類型,比如這里使用readChar方法讀取第一個字符,但是為什么會輸出這個字?查看源碼:

   public final char readChar() throws IOException {
        int ch2 = in.read(); //97
        int ch3 = in.read();//98
        if ((ch2 | ch3) < 0)
            throw new EOFException();
        return (char)((ch2 << 8) + (ch3 << 0));
    }

因為Java中的char類型使用2個字節來存儲,所以這里讀取連續的兩個字節來當做一個字符。由于文件中存儲的是字母,前面已經解釋了,ch2的值應該是97,ch3的值是98,執行(ch2 << 8) + (ch3 << 0)的結果是十進制的24930,而24930在utf8中對應的就是漢字。這里只是解釋原理,不涉及如何正確讀取原始數據的問題。

在這個例子當中,DataInputStreamBufferedInputStream用于增強功能,也就是裝飾者角色,而FileInputStream是數據源,是被裝飾者,他們都有著共同的方法,并且裝飾者要持有一個被裝飾者或者其他裝飾者的引用(這里通過構造方法注入),所以他們應當有共同的父類。這些裝飾器可以自由組合,以實現不同的功能。所以,如果不這樣做的話,還有更好的實現方式來達到同樣的效果嗎?完整的繼承關系如下圖:

如何從Java IO源碼看裝飾者模式的用法

抽象類圖

如何從Java IO源碼看裝飾者模式的用法

  1. 首先有個被裝飾對象

  2. 然后有一堆的裝飾器用于增強不同的功能

  3. 裝飾器與被裝飾對象具有相同的行為(超類中的抽象方法)

  4. 裝飾器應當持有被裝飾者的引用或者其他裝飾者(持有超類的引用,多態的體現)

  5. 組合這些裝飾器和被裝飾對象(構造方法注入)

感謝各位的閱讀,以上就是“如何從Java IO源碼看裝飾者模式的用法”的內容了,經過本文的學習后,相信大家對如何從Java IO源碼看裝飾者模式的用法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

曲松县| 肇东市| 澄城县| 商都县| 徐闻县| 崇州市| 临高县| 深水埗区| 海兴县| 酒泉市| 岳池县| 蒙阴县| 阿荣旗| 神木县| 海门市| 台东市| 谷城县| 克什克腾旗| 玛沁县| 淳安县| 壤塘县| 吐鲁番市| 临颍县| 南华县| 桦川县| 滨州市| 黔西县| 伊宁市| 定远县| 明光市| 芜湖县| 上饶市| 南靖县| 磐安县| 大兴区| 成安县| 镇坪县| 襄樊市| 藁城市| 仁布县| 利津县|