[Java-12] エンコードテーブル、文字ストリーム、オブジェクトストリーム、その他のストリーム

メインコンテンツ

  • コードリスト
  • 文字出力ストリーム
  • 文字入力ストリーム
  • 文字バッファストリーム
  • 変換ストリーム
  • オブジェクトの操作フロー
  • デコレータパターン
  • commons-iojar パッケージ

1 コードリスト

1.1 考え方:

  • バイト ストリームはすべてのファイルを操作できるのに、なぜ文字ストリームを学ぶ必要があるのでしょうか?
    • バイトストリームを使用すると、テキストファイルの内容をメモリに読み込む際に文字化けが発生する場合があります
    • バイトストリームを使用して中国語をテキストファイルに書き込むと、文字化けが発生する可能性もあります

1.2 コードテーブルの概要

  • コンピュータに保存されている情報はバイナリデータで表現されており、画面上に表示される英語や漢字などの文字は、バイナリ数に変換されたものです。

  • コード表の規則に従って文字をコンピュータに保存することをエンコードといいます。

  • 同じコーディング テーブルの規則に従って、コンピューターに保存されているバイナリ データが解析されて表示されます。これをデコーディングと呼びます。

  • エンコードとデコードに使用されるコード テーブルは一貫している必要があり、一貫していないと文字化けが発生します。

  • 簡単な理解:
    • 文字 a を格納するには、まずコード テーブルで対応する数字 97 を見つけ、それをバイナリに変換する規則に従って格納する必要があります。コード
    • 読み取るときは、まずバイナリを解析してから 97 に変換し、97 を使用して初期のコード テーブル内の対応する文字を見つけます。デコードと呼ばれる
  • ASCIIコード表:
    • ASCII (情報交換のための米国標準コード、情報交換のための米国標準コード):
    • 数字、英語の大文字と小文字、およびいくつかの一般的な句読点文字が含まれます。
    • 注: ASCII コード表には中国語はありません。

    [外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-nqQ7Nr8R-1685619059845)(img\image-20210415215825911.png)]

  • GBKコード表:
    • ウィンドウ システムのデフォルトのコード テーブル。ASCII コードテーブルと互換性があり、21003 の中国語文字も含まれ、繁体字中国語文字と一部の日本語および韓国語文字をサポートします。
    • 注: GBK は中国語のコード テーブルであり、中国語は 2 バイトの形式で格納されます。ただし、世界すべての国のテキストが含まれているわけではありません。
  • Unicode コード表:
    • 国際機関 ISO によって開発された、コンピュータ サイエンスの分野の業界標準である統一ユニバーサル コード テーブルであり、世界のほとんどの国で共通の文字と記号がすべて含まれています。
    • ただし、表現される文字が多すぎるため、Unicode コード テーブルの数値はバイナリ形式でコンピュータに直接保存されず、最初に UTF-7、UTF-7.5、UTF-8、UTF-16、および UTF を通過します。 -32 エンコード方式はコンピュータに保存されます。最も一般的なのは UTF-8 です。
    • 注: Unicode はユニバーサル コード テーブルであり、UTF-8 エンコードの後、中国語は 3 バイトの形式で保存されます。

1.4 中国語の出現コードを読み取るバイトストリームの元のコード

  • バイトストリームはGBKやUTF-8に関係なく一度に1バイトずつ読み込むため、中国語は複数バイトであり、バイトストリームは一度に一部しか読み込めないため文字化けが発生します。

2 文字の出力ストリーム

2.1 文字ストリーム出力の概要

  • ライタークラス
    • 文字ストリームを書き込む最上位クラスはインスタンス化できない抽象クラスであり、そのサブクラスである FileWriter クラスを使用する必要があります。
  • FileWriter クラス: 文字ファイルを書き込むための便利なクラス

2.2 FileWriter のメンバー

  • 施工方法:

    • public FileWriter(File file) : 指定されたファイルパスにデータを書き込みます
    • public FileWriter(String fileName) : 指定された文字列パスにデータを書き込みます
  • メンバーメソッド:

    • 無効な書き込み(int c) 文字を書く
      void write(char[] cbuf) 文字配列を書き込む
      void write(char[] cbuf, int off, int len) 文字配列の一部を書き込む
      void write(文字列str) 文字列を書く
      void write(String str, int off, int len) 文字列の一部を書き込む
    • 流す() ストリームを更新し、データの書き込みを続行します
      近い() ストリームを閉じてリソースを解放しますが、閉じる前にストリームをフラッシュします。閉じるとデータを書き込むことができなくなります

2.3 FileWriter がデータを書き込む手順

  • 1 文字出力ストリームオブジェクトを作成する
    • 注:
      ファイルが存在しない場合は作成されます。ただし、親パスが存在することを確認してください。
      ファイルが存在する場合は空にします
  • 2 書き込みデータ
    • 注:
      int 型の整数を書き込む場合、実際に書き込まれるのは、コード テーブル上の整数に対応する文字です。
      文字列データを書き出す場合は、文字列そのものをそのまま書き出します。
  • 3 リリース リソース
    • 注:
      ストリームが使用されるたびにリソースを解放する必要があります。
  • package com.bn.writer_demo;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
        Writer类 : 写入字符流的最顶层的类 , 是一个抽象类 ,不能实例化
        需要使用其子类FileWriter类
    
        FileWriter类 : 用来写入字符文件的便捷类
        构造方法 :
            public FileWriter(File file) : 往指定的File路径中写入数据
            public FileWriter(String fileName) : 往指定的String路径中写入数据
        成员方法
            void write​(int c)	写一个字符
            void write​(char[] cbuf)	写入一个字符数组
            void write​(char[] cbuf, int off, int len)	写入字符数组的一部分
            void write​(String str)	写一个字符串
            void write​(String str, int off, int len)	写一个字符串的一部分
            flush()	刷新流,还可以继续写数据
            close()	关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
     */
    public class WriterDemo1 {
          
          
        public static void main(String[] args) throws IOException {
          
          
            // 创建字符输出流对象
            // 如果文件不存在会创建一个空的文件
            // 如果文件存在 , 会把文件中的内容清空
            FileWriter fw = new FileWriter("day12_demo\\charstream2.txt");
    
            // 写数据
            fw.write('a');
            fw.write('b');
            // 刷新流 , 把流中的数据刷到硬盘中 , 刷新之后可以继续写数据
            // fw.flush();
    
            // 释放资源
            // 关闭流 , 但是会先刷新流
            fw.close();
            // 一旦关闭流无法写数据
            // fw.write('c');
        }
    }
    
    
    package com.bn.writer_demo;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
        Writer类 : 写入字符流的最顶层的类 , 是一个抽象类 ,不能实例化
        需要使用其子类FileWriter类
    
        FileWriter类 : 用来写入字符文件的便捷类
        构造方法 :
            public FileWriter(File file) : 往指定的File路径中写入数据
            public FileWriter(String fileName) : 往指定的String路径中写入数据
        成员方法
            void write​(int c)	写一个字符
            void write​(char[] cbuf)	写入一个字符数组
            void write​(char[] cbuf, int off, int len)	写入字符数组的一部分
            void write​(String str)	写一个字符串
            void write​(String str, int off, int len)	写一个字符串的一部分
            flush()	刷新流,还可以继续写数据
            close()	关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
     */
    public class WriterDemo2 {
          
          
        public static void main(String[] args) throws IOException {
          
          
            // 创建字符输出流对象
            FileWriter fw = new FileWriter("day12_demo\\charstream2.txt");
    
            // 写数据
    //        void write​(int c)	写一个字符
    //        fw.write('a');
    //        fw.write('b');
    //        fw.write('c');
    
    //        void write​(char[] cbuf)	写入一个字符数组
            char[] chs = {
          
          'a', 'b', 'c', 'd', 'e'};
    //        fw.write(chs);
    
    //        void write​(char[] cbuf, int off, int len)	写入字符数组的一部分
    //        fw.write(chs , 2 , 3);
    
    //        void write​(String str)	写一个字符串
    //        fw.write("abcadaasda");
    
    //        void write​(String str, int off, int len)	写一个字符串的一部分
    //        fw.write("abnacna", 3, 2);
    
            // 释放资源
            fw.close();
        }
    }
    
    

2.4 文字出力ストリームの演習

  • package com.bn.writer_demo;
    
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.Scanner;
    
    /*
        需求 : 将用户键盘录入的用户名和密码保存到本地实现永久化存储。
        要求 : 用户名和密码在文件中各占一行
    
        步骤:
            1 用户键盘录入用户名
            2 创建字符输出流对象
            3 将用户名和密码写到本地文件中
     */
    public class WriterTest {
          
          
        public static void main(String[] args) throws IOException {
          
          
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入用户名:");
            String username = sc.nextLine();
    
            System.out.println("请输入密码:");
            String password = sc.nextLine();
    
            // 创建字符输出流对象
            FileWriter fw = new FileWriter("day12_demo\\user.txt");
            // 往文件中写入用户名和密码
            fw.write(username);
            // 换行
            fw.write("\r\n");
            fw.write(password);
            // 刷新
            fw.flush();
            // 释放资源
            fw.close();
        }
    }
    
    

3文字入力ストリーム

3.1 バイト入力ストリームの概要

  • リーダークラス:
    • 文字ストリームを読み取る最上位クラスは、インスタンス化できない抽象クラスです。
    • そのサブクラス FileReader クラスを使用する必要がある
  • ファイルリーダークラス:
    • 文字ファイルを読み取るための便利なクラス

3.2 FileReader のメンバー

  • 施工方法:

    • public FileReader(File file) : 指定されたファイルパスからデータを読み取ります
    • public FileReader(String fileName) : 指定された String パスからデータを読み取ります
  • メンバーメソッド:

    • int read() 文字データを1つずつ読み込む
      int read(char[] cbuf) 文字配列データを一度に 1 つずつ読み取る
  • package com.bn.reader_demo;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    /*
        Reader类 : 读取字符流的最顶层的类 , 是一个抽象类 ,不能实例化
        需要使用其子类FileReader类
    
        FileReader类 : 用来读取字符文件的便捷类
    
        构造方法 :
            public FileReader(File file) : 从指定的File路径中读取数据
            public FileReader(String fileName) : 从指定的String路径中读取数据
    
        成员方法 :
            int read​() : 一次读一个字符数据
            int read​(char[] cbuf)	 : 一次读一个字符数组数据
     */
    public class ReaderDemo1 {
          
          
        public static void main(String[] args) throws IOException {
          
          
            // 创建字符输入流对象
            FileReader fr = new FileReader("day12_demo\\charstream.txt");
    
            // 一次读一个字符数据
            int ch;
            while ((ch = fr.read()) != -1) {
          
          
                System.out.print((char) ch);
            }
    
            // 释放资源
            fr.close();
        }
    }
    
    
  • package com.bn.reader_demo;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    /*
        Reader类 : 读取字符流的最顶层的类 , 是一个抽象类 ,不能实例化
        需要使用其子类FileReader类
    
        FileReader类 : 用来读取字符文件的便捷类
    
        构造方法 :
            public FileReader(File file) : 从指定的File路径中读取数据
            public FileReader(String fileName) : 从指定的String路径中读取数据
    
        成员方法 :
            int read​()	一次读一个字符数据
            int read​(char[] cbuf)	一次读一个字符数组数据
     */
    public class ReaderDemo2 {
          
          
        public static void main(String[] args) throws IOException {
          
          
            // 创建字符输入流对象
            FileReader fr = new FileReader("day12_demo\\charstream.txt");
    
            // 一次读一个字符数组数据
            char[] chs = new char[1024];
            int len;
            while ((len = fr.read(chs)) != -1) {
          
          
                System.out.println(new String(chs, 0, len));
            }
            // 释放资源
            fr.close();
        }
    }
    
    

4文字のバッファリングされたストリーム

4.1 文字バッファストリーム

  • BufferedWriter: データを効率的に書き込むことができます
  • BufferedReader: データをメモリに効率的に読み取ることができます
  • 注: 文字バッファ ストリームには読み取りと書き込みの機能はなく、バッファを提供するだけであり、実際の読み取りと書き込みは依然として構築によって受け取られる基本的な文字ストリームに依存する必要があります。
  • 施工方法:
    • public BufferedWriter(Writer out) : 構築メソッドは基本的な文字出力ストリームを受け取る必要があります
    • public BufferedReader(Reader in): 構築メソッドは基本的な文字入力ストリームを受け取る必要があります。
package com.bn.bufferedstream_demo;

import java.io.*;

/*
    需求 : 使用字符缓冲流复制纯文本文件
    将当日课程资料中的 ‘斗罗大陆.txt’ 复制到当前模块下 'copy.txt'
 */
public class BufferedStreamDemo1 {
    public static void main(String[] args) throws IOException {
        // 创建高效的字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("D:\\传智播客\\上海-JavaSE进阶面授\\day12【缓冲流、转换流、序列化流、装饰者模式、commons-io工具包】\\资料\\斗罗大陆.txt"));
        // 创建高效的字符输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("day12_demo\\copy.txt"));

        // 一次读写一个字符
//        int ch;
//        while ((ch = br.read()) != -1) {
//            bw.write(ch);
//        }

        // 一次读写一个字符数组
        char[] chs = new char[1024];
        int len;
        while ((len = br.read(chs)) != -1) {
            bw.write(chs, 0, len);
        }
        // 释放资源
        br.close();
        bw.close();
    }
}

4.2 文字バッファストリームに特有の機能

  • BufferedWriterクラス
    • void newLine(): 行区切り文字を書き込みます。これにより、オペレーティング システムに応じて異なる行区切り文字が書き込まれます。
  • BufferedReader クラス
    • public String readLine() : ファイルからデータ行を読み取ります。改行記号は含まれておらず、ファイルの最後まで読み取ると null を返します。
  • package com.bn.bufferedstream_demo;
    
    import java.io.*;
    
    /*
        1 字符缓冲流:
            BufferedWriter:可以将数据高效的写出
            BufferedReader:可以将数据高效的读入到内存
    
        2 字符缓冲流特有功能
            BufferedWriter类
                void newLine​():写一个行分隔符,会根据操作系统的不同,写入不同的行分隔符
            BufferedReader类
                public String readLine​() :读取文件一行数据, 不包含换行符号 ,  读到文件的末尾返回null
    
            远桥之下泛莲舟
            岱岩石上松溪流
            万仞翠山梨亭在
            莫闻空谷声悠悠
     */
    public class BufferedStreamDemo2 {
          
          
        public static void main(String[] args) throws IOException {
          
          
    
            // 创建高效的字符输出流对象
            BufferedWriter bw = new BufferedWriter(new FileWriter("day12_demo\\abc.txt"));
            // void newLine​():写一个行分隔符,会根据操作系统的不同,写入不同的行分隔符
            bw.write("远桥之下泛莲舟");
            bw.newLine();
            bw.write("岱岩石上松溪流");
            bw.newLine();
            bw.write("万仞翠山梨亭在");
            bw.newLine();
            bw.write("莫闻空谷声悠悠");
            bw.flush();
    
            // 创建高效的字符输入流对象
            BufferedReader br = new BufferedReader(new FileReader("day12_demo\\abc.txt"));
            // public String readLine​() :读取文件一行数据, 不包含换行符号 ,  读到文件的末尾返回null
    //        String s = br.readLine();
    //        System.out.println(s);
    //        s = br.readLine();
    //        System.out.println(s);
    //        s = br.readLine();
    //        System.out.println(s);
    //        s = br.readLine();
    //        System.out.println(s);
    //        System.out.println("============");
    //        s = br.readLine();
    //        System.out.println(s);
    //        s = br.readLine();
    //        System.out.println(s);
    
            // 循环改进
            String line;
            while((line = br.readLine()) != null){
          
          
                System.out.println(line);
            }
    
            // 释放资源
            br.close();
            bw.close();
        }
    }
    
    

4.3 文字バッファストリームの演習

package com.bn.bufferedstream_demo;

import java.io.*;
import java.util.Arrays;

/*
    需求:读取文件中的数据 : 33 22 11 55 44
    排序后 : 11 22 33 44 55  再次写到本地文件

    步骤 :
        1 创建高效的字符输入流对象
        2 读取文件中的一行数据
        3 将数据按照空格切割
        4 把字符串数组转成int类型数组
        5 对int类型的数组进行排序
        6 创建高效的字符输出流对象
        7 遍历数组,把数组中的数据写入到文件中
        8 释放资源
 */
public class BufferedStreamDemo3 {
    public static void main(String[] args) throws IOException {
        // 1 创建高效的字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("day12_demo\\sort.txt"));
        // 2 读取文件中的一行数据
        String line = br.readLine();
        // 3 将数据按照空格切割
        String[] strs = line.split(" ");
        // 4 把字符串数组转成int类型数组
        int[] arr = new int[strs.length];
        for (int i = 0; i < strs.length; i++) {
            arr[i] = Integer.parseInt(strs[i]);
        }
        // 5 对int类型的数组进行排序
        Arrays.sort(arr);
        // 6 创建高效的字符输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("day12_demo\\sort.txt"));
        // 7 遍历数组,把数组写入到文件中
        for (int i = 0; i < arr.length; i++) {
            bw.write(arr[i] + " ");
            bw.flush();
        }
        // 8 释放资源
        br.close();
        bw.close();
    }
}

5 変換ストリーム

5.1 変換フローの概要

  • 変換ストリームは、バイト ストリームと文字ストリームの間で変換するためのブリッジです。

5.2 変換ストリームの分類

  • InputStreamReader はバイト ストリームから文字ストリームへのブリッジです

    • public InputStreamReader(InputStream in) : デフォルトのエンコーディングを使用して、InputStreamReader を作成します。
    • public InputStreamReader(InputStream in , String charsetName) : 指定されたエンコーディングを使用して、InputStreamReader を作成します。
  • OutputStreamWriter は文字ストリームからバイト ストリームへのブリッジです

    • public OutputStreamWriter(OutputStream out) : デフォルトの文字エンコーディングを使用する OutputStreamWriter を作成します。
    • public OutputStreamWriter(OutputStream out, String charsetName) : 指定されたエンコーディングを使用して OutputStreamWriter を作成します。
  • 練習
    package com.bn.conversion_demo;
    
    import java.io.*;
    
    /*
        转换流就是来进行字节流和字符流之间转换的桥梁
    
        InputStreamReader是从字节流到字符流的桥梁
            public InputStreamReader(InputStream in) : 创建一个使用默认编码的 InputStreamReader。
            public InputStreamReader(InputStream in ,  String charsetName) : 创建使用指定编码的 InputStreamReader。
    
        OutputStreamWriter是从字符流到字节流的桥梁
            public OutputStreamWriter(OutputStream out) : 创建使用默认字符编码的 OutputStreamWriter
            public OutputStreamWriter(OutputStream out,  String charsetName) : 创建使用指定编码的 OutputStreamWriter。
    
    
        需求1 : 使用转换流 , 把以下数据按照GBK的编码写入文件 , 在使用GBK的编码读取数据
        数据如下 :
            远桥之下泛莲舟
            岱岩石上松溪流
            万仞翠山梨亭在
            莫闻空谷声悠悠
     */
    public class ConversionDemo2 {
          
          
        public static void main(String[] args) throws IOException {
          
          
            // 创建转换输出流
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day12_demo\\conversion.txt"), "GBK");
            osw.write("远桥之下泛莲舟");
            osw.write("\r\n");
            osw.write("岱岩石上松溪流");
            osw.write("\r\n");
            osw.write("万仞翠山梨亭在");
            osw.write("\r\n");
            osw.write("莫闻空谷声悠悠");
            osw.write("\r\n");
            osw.close();
    
            // 创建转换输入流
            InputStreamReader isr = new InputStreamReader(new FileInputStream("day12_demo\\conversion.txt"), "GBK");
            int ch;
            while ((ch = isr.read()) != -1) {
          
          
                System.out.print((char) ch);
            }
            isr.close();
        }
    }
    
    
    package com.bn.conversion_demo;
    
    import java.io.*;
    
    /*
        转换流就是来进行字节流和字符流之间转换的桥梁
    
        InputStreamReader是从字节流到字符流的桥梁
            public InputStreamReader(InputStream in) : 创建一个使用默认编码的 InputStreamReader。
            public InputStreamReader(InputStream in ,  String charsetName) : 创建使用指定编码的 InputStreamReader。
    
        OutputStreamWriter是从字符流到字节流的桥梁
            public OutputStreamWriter(OutputStream out) : 创建使用默认字符编码的 OutputStreamWriter
            public OutputStreamWriter(OutputStream out,  String charsetName) : 创建使用指定编码的 OutputStreamWriter。
    
        需求2 :  将模块根目录中GBK编码的文本文件 , 转换为UTF-8编码的文本文件
     */
    public class ConversionDemo2 {
          
          
        public static void main(String[] args) throws IOException {
          
          
    
            // 创建转换输入流
            InputStreamReader isr = new InputStreamReader(new FileInputStream("day12_demo\\GBK编码的文件.txt"), "GBK");
    
            // 创建转换输出流
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day12_demo\\UTF编码的文件.txt"), "UTF-8");
    
            int ch;
            while ((ch = isr.read()) != -1) {
          
          // 以GBK编码进去读取
                osw.write(ch);// 以UTF-8编码进行写入
            }
    
            // 释放资源
            isr.close();
            osw.close();
        }
    }
    
    

6 オブジェクトの操作フロー

6.1 オブジェクト操作フローの概要

  • オブジェクトをバイトの形式でローカル ファイルに書き込むことができます。ファイルを直接開くと、ファイルを読み取ることができません。オブジェクト操作ストリームを使用してメモリに再度読み取る必要があります。

6.2 オブジェクト操作フローの分類

  • オブジェクト出力ストリーム:
    • オブジェクト操作出力ストリーム (オブジェクト直列化ストリーム): オブジェクトをローカル ファイルに書き込むか、オブジェクトをネットワークに転送します。
  • オブジェクト入力ストリーム:
    • オブジェクト操作入力ストリーム(オブジェクト逆シリアル化ストリーム):ローカルファイルに書き込まれたオブジェクトをメモリに読み込む、またはネットワーク上で送信されたオブジェクトを受信する

6.3 オブジェクト操作フローの考慮事項

  • 注: クラス オブジェクトをシリアル化する必要がある場合、このクラスは Serializable インターフェイスを実装する必要があります。

    • Serializable インターフェイスの意味:
      • 1 は抽象メソッドを持たないマークされたインターフェイスです
      • 2 クラスがこのインターフェイスを実装している限り、このクラスのオブジェクトはシリアル化できることを意味します
  • オブジェクトシリアル化ストリームを使用してオブジェクトをシリアル化した後、そのオブジェクトが属する Javabean クラスを変更すると、データの読み取りに問題が発生しますか?

    • 問題が発生し、InvalidClassException がスローされます。
  • 何か問題が発生した場合、どうやって解決すればよいでしょうか?

    • オブジェクトが属するクラスにserialVersionUIDを追加します。
    • プライベート静的最終ロングシリアルバージョンUID = 42L;
  • オブジェクト内のメンバー変数の値をシリアル化したくない場合、それを実現するにはどうすればよいでしょうか?

  • transient キーワードをメンバー変数に追加すると、このキーワードでマークされたメンバー変数はシリアル化プロセスに参加しません。

  • package com.bn.objectstream_demo;
    
    
    import java.io.Serializable;
    
    /*
        如果此类对象想要被序列化 , 那么此类需要实现Serializable接口
        Serializable接口的含义 :
            是一个标记性接口 , 里面没有任何抽象方法
            只要一个类实现了此接口 , 表示此类的对象可以被序列化
     */
    public class User implements Serializable {
        /*
            问题分析 :
                serialVersionUID : 序列号
                序列号是根据类的信息进行生成的
                如果没有自己给出序列号 , JVM会根据类的信息自动计算一个序列号
                如果改动了类的信息 , 那么JVM会重新计算一个序列号
    
                第一步 : 把对象序列化到本地中 , 序列号为 -4446663370728791812 也会存储到本地中
                第二步 : 我们自己修改了类 , 会重新计算一个新的序列号 2908680347500030933
                第三步 : 当把对象读到内存中时 , 本地中的序列号和类中的序列号不一致就会发生 InvalidClassException异常
    
            解决方案 :
                我们自己手动给出序列号, 不让虚拟机自动生成 , 并且这个值恒久不变
                private static final long serialVersionUID = 值L;
         */
    
        private static final long serialVersionUID = 111L;
    
        private String username;
        private transient String password;
    
        public User() {
        }
    
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }
    

6.4 オブジェクト操作フローの演習

7つの装飾デザインパターン

  • デザインパターン: 多くの開発者による継続的なテストを経てまとめられた一連の優れたコーディングスタイル

学習目標

  • Decorator デザイン パターンの使用に精通していること

内容説明

【1。概要

  • デコレーション モードとは、元のクラスを変更せず、継承も使用せずにオブジェクトの機能を動的に拡張することを指します。

  • 機能拡張に継承テクノロジを使用しないでください。これにより結合が軽減されます。

  • 使用原則:
    • 装飾クラスと装飾クラスは、共通の親タイプを持つ必要があります。
      • 以前学習したBufferedWriterとFileWriterは装飾デザインパターンです
      • BufferedWriter の親クラスは Writer です
      • FileWriter の親クラスも Writer です
      • FileWriter オブジェクトを BufferedWriter の構築に渡すので、BufferedWriter は装飾されたクラスであり、FileWriter は装飾されたクラスであることが理解できます。
      • BufferedWriterはFileWriterの機能を強化しました
    • 装飾されたクラスのコンストラクターは、装飾されたクラスのオブジェクトを受け取る必要があります
      • FileWriter fw = new FileWriter("パス");
      • BufferedWriter bw = new BufferedWriter(fw);
    • 拡張・拡張したい機能をデコレーションクラスで拡張する
      • BufferedWriterはFileWriterと同じ機能を持ち、どちらもWriterにデータを書き込む機能を持ちます。
      • ただし、BufferedWriter はバッファを提供します。これは FileWriter の機能を拡張するのと同等です。
    • 拡張しない機能については直接電話してください
      • 拡張機能は親クラスから直接継承できません

[2] コードの練習

Star インターフェイスとそのサブタイプ LiuDeHua が存在することが知られています。

public interface Star {
    
    
    public abstract void sing();
    public abstract void dance();
}

要件: LiuDeHua クラスを変更せず、継承手法も使用せずに、LiuDeHua の sing 関数を動的に拡張します。

LiuDeHua は、歌唱機能を拡張する必要がある装飾されたクラスです

アイデア:

LiuDehua クラスを装飾および強化するための装飾クラスを定義します。

ステップ:

  • LiuDeHua クラスを作成し、インターフェース Star [装飾クラス] を実装します。

  • Starを実装する装飾クラスLiuDeHuaWrapperを定義する [装飾クラス]

  • 装飾クラスのメンバー変数型を LiuDeHua として定義すると、コンストラクターを使用して装飾クラス オブジェクトを渡すことができます。

  • デコレーションクラスのsingメソッドの機能を拡張する

  • 踊ることに変わりはない

  • テスト クラスは、装飾クラスのオブジェクトと装飾クラスのオブジェクトをそれぞれ作成します。装飾されたクラス オブジェクトを装飾されたクラス オブジェクトに設定する Andy Lau オブジェクト

package com.bn.design_demo;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;

/*
    装饰模式指的是在不改变原类, 不使用继承的基础上,动态地扩展一个对象的功能

    使用原则 :
        1. 装饰类和被装饰类需要有共同的父类型。
        2. 装饰类要传入被装饰类的对象
        3. 在装饰类中把要增强扩展的功能进行扩展
        4. 对于不要增强的功能直接调用


    需求 : 在不改变LiuDeHua类,及不使用继承的技术前提下,动态的扩展LiuDeHua的sing功能。
            LiuDeHua就是一个被装饰类 , 需要对唱歌的功能进行扩展
    步骤:
        1. 创建LiuDeHua类并实现接口Star【被装饰类】
        2. 定义一个装饰类LiuDeHuaWrapper实现Star 【装饰类】
        3. 在装饰类里面定义一个成员变量类型是LiuDeHua,可以使用构造方法进行传入被装饰类对象。
        4. 在装饰类中对sing方法进行功能扩展
        5. 对dance不做改动
        6. 测试类分别创建装饰类的对象和被装饰类的对象。将被装饰类对象刘德华对象设置给装饰类对象
 */
public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        // 被装饰类对象
        LiuDeHua huaZai = new LiuDeHua();// 0x001

        // 装饰类对象
        LiuDeHuaWrapper liuDeHuaWrapper = new LiuDeHuaWrapper(huaZai);
        liuDeHuaWrapper.sing();
        liuDeHuaWrapper.dance();

//        // 被装饰类对象
//        FileWriter fw = new FileWriter("路径");
//        // 装饰类对象
//        BufferedWriter bw = new BufferedWriter(fw);
    }
}


// 1. 创建LiuDeHua类并实现接口Star【被装饰类】
class LiuDeHua implements Star {
    
    

    @Override
    public void sing() {
    
    
        System.out.println("唱忘情水...");
    }

    @Override
    public void dance() {
    
    
        System.out.println("华仔在跳老年迪斯高..");
    }
}

// 2. 定义一个装饰类LiuDeHuaWrapper实现Star 【装饰类】
class LiuDeHuaWrapper implements Star {
    
    
    // 3. 在装饰类里面定义一个成员变量类型是LiuDeHua,可以使用构造方法进行传入被装饰类对象。
    private LiuDeHua huaZai;// 0x001

    public LiuDeHuaWrapper(LiuDeHua huaZai) {
    
    // 0x001
        this.huaZai = huaZai;
    }

    @Override
    public void sing() {
    
    
        // 4. 在装饰类中对sing方法进行功能扩展
        System.out.print("华仔深情");
        huaZai.sing();
    }

    @Override
    public void dance() {
    
    
        // 5. 对dance不做改动
        huaZai.dance();
    }
}


// 明星接口 , 装饰类和被装饰类的父类型
interface Star {
    
    
    public abstract void sing(); // 唱歌

    public abstract void dance();// 跳舞
}

内容概要

  1. 装飾クラスと装飾クラスは、共通の親タイプを持つ必要があります。
  2. 装飾クラスは、装飾されたクラスのオブジェクトを渡す必要があります。
  3. 拡張・拡張したい機能をデコレーションクラスで拡張する
  4. 拡張しない機能については直接電話してください

9 commons-io ツールキット (ファイルコピーの最適化)

目標

  • commons-io ツールキットのインポートと使用方法に慣れておく

内容説明

[1] サードパーティライブラリのインポート

  1. commons-io 関連の jar パッケージをダウンロードします; http://commons.apache.org/proper/commons-io/

  2. commons-io-2.6.jar パッケージを指定したモジュールの lib ディレクトリにコピーします。

  3. commons-io-2.6.jarをプロジェクトに追加します

【2】API

1) org.apache.commons.io.IOUtils クラス

public static int copy(InputStream in, OutputStream out):
	把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以下)
    
public static long copyLarge(InputStream in, OutputStream out):
	把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以上)

package com.bn.commons_io;

import org.apache.commons.io.IOUtils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/*
    org.apache.commons.io.IOUtils类

    public static int copy(InputStream in, OutputStream out):
	把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以下)

    public static long copyLarge(InputStream in, OutputStream out):
	把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以上)
 */
public class Test1 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        IOUtils.copy(new FileInputStream("D:\\安装包\\好看的图片\\liqin.jpg") , new FileOutputStream("day12_demo\\copy.jpg"));
    }
}

2)org.apache.commons.io.FileUtils

public static void copyFileToDirectory(final File srcFile, final File destFile): 
	复制文件到另外一个目录下。
public static void copyDirectoryToDirectory(File src , File dest ):
	复制src目录到dest位置。

コードの練習:

package com.bn.commons_io;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

/*
    org.apache.commons.io.FileUtils

    public static void copyFileToDirectory(final File srcFile, final File destFile):
	复制文件到另外一个目录下。

    public static void copyDirectoryToDirectory(File src , File dest ):
	复制src目录到dest目录中。
 */
public class Test2 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileUtils.copyDirectoryToDirectory(new File("D:XX") , new File("D:"));
    }
}

内容概要

commons-io を使用すると、ファイルの IO コピー操作を簡素化できます。

おすすめ

転載: blog.csdn.net/wanghaoyingand/article/details/130994665