1. 程式人生 > 實用技巧 >java複習_進階

java複習_進階


title: java複習_進階
tags:

  • java
    categories:
  • java
    abbrlink: 47946
    date: 2020-08-10 21:48:00

Java複習

本文主要進行java的複習與進階,複習部分參考java基礎,這裡只包含一些常用的API,進階部分預計包含javaBean,反射,泛型,註解,集合,IO

API

math.API

BigDecimal

public class LearnString_A {
    public static void main(String[] args) {
        BigDec big_data = new BigDec();
        System.out.println(big_data.do_func());
    }
}
class BigDec {
    public double do_func(){
        BigDecimal a = new BigDecimal("2.0008");
        BigDecimal b = new BigDecimal("1.00009");
        BigDecimal res =  a.subtract(b);
        //result.setScale(1,BigDecimal.ROUND_HALF_UP);//四捨五入
        return res.doubleValue();
    }
}

util.API

Scanner

Scanner輸入與hasNext緩衝區輸入判斷

toCharArray進行字串分割與Character的字元判斷

public void CharSplit(){
    Scanner scanner = new Scanner(System.in);
    if (scanner.hasNext()){
        String input_data = scanner.next();
        for (char c: input_data.toCharArray()){
            //                System.out.println(c);
            if (Character.getType(c)==Character.OTHER_LETTER){
                System.out.println("chinese");
            }else if (Character.isDigit(c)){
                System.out.println(String.format("%-8d",Integer.parseInt(String.valueOf(c))));
            }else  if(Character.isLetter(c)){
                System.out.println(String.format("%-8s", "letter"));
            }else {
                System.out.println(String.format("%-10s", "other character"));
            }
        }
        scanner.close();
    }

String

String不可變

StringBuilder

可變物件,預分配緩衝區,向StringBuilder新增字元時,不會建立新的臨時物件

StingBuilder支援鏈式操作,使用append進行拼接,每個函式return this -> getValue()

StringJoiner

可以指定開頭和結尾,類似於python的join

public String StrConcat() {
    String[] names = {"Bob", "Alice", "Smith"};
    StringJoiner origin_str = new StringJoiner(", ","Hello","!~~");
    for (String name:names){
        origin_str.add(name);
    }
    return origin_str.toString();
}

javaBean

BeanInfo

public class BeanLearn {
    public static void main(String[] args) throws Exception {
        BeanInfo info = Introspector.getBeanInfo(Person.class);
        for(PropertyDescriptor pd:info.getPropertyDescriptors()){
            System.out.println(pd.getName());
            System.out.println(pd.getReadMethod());
            System.out.println(pd.getWriteMethod());
        }
    }
}

classpath和jar

classpath

JVM環境變數,用於解決類依賴(後續有maven來解決此種依賴)

java -classpath .;system_path java -cp ,;system_path

原則上不支援設定classpath,只有在單獨需求執行某個java檔案和其依賴時再使用

jar

由於jar包實際上就是zip包,可以直接打壓縮,字尾名zip改為jar就可以建立一個jar包

關於具體的jar包的格式,只需要注意,bin目錄不能作為第一級別目錄,打包jar包可以使用IDEA實現

java -jar hello.jar執行jar包

內部類

內部類擁有外部類的訪問許可權,且可以變相實現多重繼承

public class OuterClass {
    private String name;
    private int age;
    class InnerClass {
        public InnerClass() {
            name = "Mr.Wu";
            age = 25;
        }
    }
}

反射,主界,泛型集合與IO

反射

訪問欄位

  • Field getField(name):根據欄位名獲取某個public的field(包括父類)
  • Field getDeclaredField(name):根據欄位名獲取當前類的某個field(不包括父類)
  • Field[] getFields():獲取所有public的field(包括父類)
  • Field[] getDeclaredFields():獲取當前類的所有field(不包括父類)

一個Field物件包含了一個欄位的所有資訊:

  • getName():返回欄位名稱,例如,"name"
  • getType():返回欄位型別,也是一個Class例項,例如,String.class
  • getModifiers():返回欄位的修飾符,它是一個int,不同的bit表示不同的含義。
public static void main(String[] args) throws NoSuchFieldException {
    Class<Student> stdClass =  Student.class;
    System.out.println(stdClass.getField("name"));
    System.out.println(stdClass.getField("score"));
    System.out.println(stdClass.getDeclaredField("grade"));
    System.out.println(Arrays.toString(stdClass.getFields()));
}
class Person{
    public String name;
}
class Student extends Person{
    public int score;
    private int grade;
}
//類物件+類屬性物件 -> 類屬性物件繫結例項 -> 得到值
Class<Student> stdClass = Student.class;
Object stu1 = new Student();
Field fie = stdClass.getField("name");
fie.setAccessible(true);
Object value = fie.get(stu1);
System.out.println(value);
fie.set(stu1,123);
System.out.println(fie.get(stu1));

此外,setAccessible(true)可能會失敗。如果JVM執行期存在SecurityManager,那麼它會根據規則進行檢查,有可能阻止setAccessible(true)。例如,某個SecurityManager可能不允許對javajavax開頭的package的類呼叫setAccessible(true),這樣可以保證JVM核心庫的安全

訪問方法

  • Method getMethod(name, Class...):獲取某個publicMethod(包括父類)
  • Method getDeclaredMethod(name, Class...):獲取當前類的某個Method(不包括父類)
  • Method[] getMethods():獲取所有publicMethod(包括父類)
  • Method[] getDeclaredMethods():獲取當前類的所有Method(不包括父類)

一個Method物件包含一個方法的所有資訊:

  • getName():返回方法名稱,例如:"getScore"
  • getReturnType():返回方法返回值型別,也是一個Class例項,例如:String.class
  • getParameterTypes():返回方法的引數型別,是一個Class陣列,例如:{String.class, int.class}
  • getModifiers():返回方法的修飾符,它是一個int,不同的bit表示不同的含義。
public static void main(String[] args) throws Exception {
     Class<Student> stdClass = Student.class;
    // 獲取public方法getScore,引數為String:
    System.out.println(Arrays.toString(stdClass.getMethod("getScore", String.class).getParameterTypes()));
    // 獲取繼承的public方法getName,無引數:
    System.out.println(stdClass.getMethod("getName").getReturnType());
    // 獲取private方法getGrade,引數為int:
    System.out.println(stdClass.getDeclaredMethod("getGrade", int.class));
}
//通過反射呼叫方法 方法物件+類物件 -> 方法物件繫結例項 -> 得到結果
 Class<Student> stdClass = Student.class;
Object stu = new Student();
Method method = stdClass.getMethod("getScore", String.class);
Method.setAccessible(true)
// 靜態方法時使用null來代替stu物件(因為靜態方法無法new獲取,直接通過method即可繫結)
char[] res = (char[]) method.invoke(stu,"test");
System.out.println(res.getClass());
//
class Student extends Person {
    public int getScore(String type) {
        return 99;
    }
    private int getGrade(int year) {
        return 1;
    }
}
class Person {
    public String getName() {
        return "Person";
    }
}

注:仍然遵循多型原則

呼叫構造方法

注意:只能呼叫無參構造方法

Person p = Person.class.newInstance();

  • getConstructor(Class...):獲取某個publicConstructor
  • getDeclaredConstructor(Class...):獲取某個Constructor
  • getConstructors():獲取所有publicConstructor
  • getDeclaredConstructors():獲取所有Constructor
Constructor<Student> cons1 = Student.class.getConstructor(String.class, String.class);
Student stu = (Student)cons1.newInstance("2233","213");
System.out.println(stu.getGrade());
class Student extends Person {
    private final String score;
    private final String grade;
    public Student(String score, String grade) {
        super();
        this.score = score;
        this.grade = grade;
    }
    public String getScore() {
        return score;
    }
    public String getGrade() {
        return grade;
    }
}

獲取父類物件

Class<? super Student> n = stdClass.getSuperclass();
System.out.println(n);//class Person
System.out.println(n.getSuperclass());//class java.lang.Object
// 獲取介面,只返回當前類的,無父類實現的介面
Class s = Integer.class;
Class[] is = s.getInterfaces();

如果是兩個Class例項,要判斷一個向上轉型是否成立,可以呼叫isAssignableFrom()

Integer.class.isAssignableFrom(Number.class); // false,因為Number不能賦值給Integer

Java註解

元註解

最常用的元註解是@Target。使用@Target可以定義Annotation能夠被應用於原始碼的哪些位置:

  • 類或介面:ElementType.TYPE
  • 欄位:ElementType.FIELD
  • 方法:ElementType.METHOD
  • 構造方法:ElementType.CONSTRUCTOR
  • 方法引數:ElementType.PARAMETER

另一個重要的元註解@Retention定義了Annotation的生命週期:

  • 僅編譯期:RetentionPolicy.SOURCE
  • 僅class檔案:RetentionPolicy.CLASS
  • 執行期:RetentionPolicy.RUNTIME

使用@Repeatable這個元註解可以定義Annotation是否可重複。

使用@Inherited定義子類是否可繼承父類定義的Annotation@Inherited僅針對@Target(ElementType.TYPE)型別的annotation有效,並且僅針對class的繼承,對interface的繼承無效:

處理註解

因為註解定義後也是一種class,所有的註解都繼承自java.lang.annotation.Annotation,因此,讀取註解,需要使用反射API。

Java提供的使用反射API讀取Annotation的方法包括:

判斷某個註解是否存在於ClassFieldMethodConstructor

  • Class.isAnnotationPresent(Class)
  • Field.isAnnotationPresent(Class)
  • Method.isAnnotationPresent(Class)
  • Constructor.isAnnotationPresent(Class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Range {
    int min() default 0;
    int max() default 255;
}
// javaBean
public class Person {
    @Range(min=1, max=20)
    public String name;

    @Range(max=10)
    public String city;
}
// 自定義檢查
void check(Person person) throws IllegalArgumentException, ReflectiveOperationException {
    // 遍歷所有Field:
    for (Field field : person.getClass().getFields()) {
        // 獲取Field定義的@Range:
        Range range = field.getAnnotation(Range.class);
        // 如果@Range存在:
        if (range != null) {
            // 獲取Field的值:
            Object value = field.get(person);
            // 如果值是String:
            if (value instanceof String) {
                String s = (String) value;
                // 判斷值是否滿足@Range的min/max:
                if (s.length() < range.min() || s.length() > range.max()) {
                    throw new IllegalArgumentException("Invalid field: " + field.getName());
                }
            }
        }
    }
}

Java泛型

泛型定義與使用 :略

泛型的坑

由於泛型在編譯時進行擦拭,即將T -> Object 所以理論上對Object進行的操作都不能直接對泛型使用

  • Object無法對基本型別(int)進行繼承或操作
  • 理論上沒有必要通過反射獲取Object(無法獲取泛型型別)
  • 理論上不能對Object進行例項化
  • 不能進行泛型的覆寫override(泛型呼叫時方法名不能為內建方法)
  • 可以繼承泛型類
public class TObject {
    public static void main(String[] args) {
        // Pair<int>pair = new Pair<>(1,2) wrong 泛型無法定義基本型別<Object>
        Pair<Integer>pair = new Pair<>(1,2);
        // 無法通過反射獲取到物件的泛型
        System.out.println(pair.getClass());
        System.out.println(Pair.class);
        // 無法判斷帶泛型的例項類
        System.out.println(pair instanceof Pair<Integer>);//exception
        // 通過反射來獲取父類的泛型的型別
        // 注意,Type-> Class + ParameterizedType + GenericArrayType + WildcardType
        InPair ip = new InPair(1,2);
        Class<InPair> inPairClass = InPair.class;
        // 獲取父類的Type物件,這裡多做一遍的目的是為了防止沒有父類(即不是繼承類的情況)
        Type t = inPairClass.getGenericSuperclass();
        if (t instanceof ParameterizedType){
            // 向下轉型為ParameterizedType
            ParameterizedType pt = (ParameterizedType) t;
            // 獲取到每個引數的Type物件(泛型可以有多個,如Map)
            Type[] types = pt.getActualTypeArguments();
            Type firstType = types[0];
            // 向下轉型為Class,這裡可以不用轉型直接輸出
            Class<?> typeClass = (Class<?>) firstType;
            System.out.println(typeClass);
            System.out.println(Arrays.toString(types));
        }
        // 簡便方式
        Type[] types = ((ParameterizedType) t).getActualTypeArguments();
        System.out.println(Arrays.toString(types));
    }
}
class Pair<T> {
    private T first;
    private T last;
    public Pair() {
    }
    public Pair(T first, T last) {
        this.first = first;
        this.last = last;
    }
    
    public T getFirst() {
        return first;
    }
    public T getLast() {
        return last;
    }
    // wrong 不能對泛型進行例項化
    public void defineTObject(){
        this.first = new T();
    }
}
class InPair extends Pair<Integer>{
    public InPair() {
        super();
    }
    public InPair(Integer first, Integer last) {
        super(first, last);
    }
}

集合

Iterable

public class userCollection {
    public static void main(String[] args) {
        UseIterate user_define_iterate = new UseIterate();
        Integer[] array = {1,2,3,4};
        List<Integer> user_list = Arrays.asList(array);
        user_define_iterate.getUser_list(user_list);
    }
}

class UseIterate {
    public static boolean isNull(List<?> p) {
        return p.isEmpty() || !(p instanceof ArrayList);
    }

    public <T> void getUser_list(List<? super T> user_list) {
        if (isNull(user_list)) {
            /*for (Object ll : user_list) {
                System.out.println(ll);
            }*/
             for(Iterator it_value =user_list.listIterator();it_value.hasNext();){
                System.out.println(it_value.next());
            }
        }
        else {
            System.out.println("null");
        }
    }
}

  • Collection頂層藉口,定義集合的約定
  • List也是頂層藉口,繼承了Collection介面,也是ArrayList LinkedList等的父類
  • Set Queue 也繼承了Collection介面,用法見下方
  • Map為key,value儲存的物件

ArrayList

ArrayList是實現了List介面的動態擴容陣列,完全代替vector,除了其不是執行緒安全的這一點

執行緒安全的List Collections.synchronizedList-> List list = Collections.synchronizedList(new ArrayList(....))

public<T> void setSyn_safe_list(List<T> syn_safe_list) {
    this.syn_safe_list = Collections.synchronizedList(new ArrayList<>(syn_safe_list));
}

編寫equals來進行contains判斷

  • 自反性(Reflexive):對於非nullx來說,x.equals(x)必須返回true
  • 對稱性(Symmetric):對於非nullxy來說,如果x.equals(y)true,則y.equals(x)也必須為true
  • 傳遞性(Transitive):對於非nullxyz來說,如果x.equals(y)truey.equals(z)也為true,那麼x.equals(z)也必須為true
  • 一致性(Consistent):對於非nullxy來說,只要xy狀態不變,則x.equals(y)總是一致地返回true或者false
  • null的比較:即x.equals(null)永遠返回false

規則

  1. 先確定例項“相等”的邏輯,即哪些欄位相等,就認為例項相等;
  2. instanceof判斷傳入的待比較的Object是不是當前型別,如果是,繼續比較,否則,返回false
  3. 對引用型別用Objects.equals()比較,對基本型別直接用==比較
public boolean equals(Object o) {
    if (o instanceof Person) {
        Person p = (Person) o;
        return Objects.equals(this.firstName, p.firstName) && Objects.equals(this.lastName, p.lastName) && this.age == p.age;
    }
    return false;
}

Vector

Vector是一個執行緒安全的容器,對內部的每個方法都簡單粗暴的上鎖,因此,訪問效率遠遠低於ArrayList

其擴容為一倍擴容,而ArrayList為0.5倍擴容

Stack

注意到Deque介面實際上擴充套件自Queue

Queue Deque
新增元素到隊尾 add(E e) / offer(E e) addLast(E e) / offerLast(E e)
取隊首元素並刪除 E remove() / E poll() E removeFirst() / E pollFirst()
取隊首元素但不刪除 E element() / E peek() E getFirst() / E peekFirst()
新增元素到隊首 addFirst(E e) / offerFirst(E e)
取隊尾元素並刪除 E removeLast() / E pollLast()
取隊尾元素但不刪除 E getLast() / E peekLast()

注意,Stack均有列表和陣列兩種形式

IO流

轉換流 : InputStreamReader OutputStreamWriter

列印流:PrintStream PrintWriter

資料流:DataInputStream DataOutputStream

物件流:ObjectinputStream ObjectOutputStream

隨機存取檔案流:RandomAccessFile

File類

  • 訪問檔名稱 getName();getPath();getAbsolutePath();getAbsoluteFile();getParent();renameTo(File newName)
  • 檔案檢測 exists();canWrite();canRead();isFile();isDirectory();lastModify()時間戳;Length()位元組數
  • 檔案操作 createNewFile();delete();mkDir();list();listFiles();
package com.learn.maven_wjh;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
public class IO_file {
    public static void main(String[] args) {
        File f = new File("D:\\Node.js\\新建資料夾\\新建文字文件.txt");
        // 可以獲取檔名或資料夾名稱
        System.out.println(f.getName());
        System.out.println(f.getPath() + ", " + f.getAbsolutePath());
        // 注意,只能識別到工程目錄
        File f1 = new File("src\\com\\learn");
        System.out.println(f1.getAbsolutePath());
//        createFile();
//        createDirection();
        File newFiles = new File(f.getParent());

    }
    public static void createFile() {
        File oldFile = new File("E:\\IDEA_CODE\\src\\com\\learn\\maven_wjh\\file_test.txt");
        // 如果檔案不存在
        if (!oldFile.exists()) {
            try {
                boolean new_judge = oldFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(oldFile.exists()){
            System.out.println(oldFile.lastModified());
            boolean delete_judge = oldFile.delete();
            System.out.println(delete_judge);
        }
    }
    public static void createDirection(){
        File direction = new File("src\\com\\learn\\java_final");
        File absolute_dir = new File(direction.getAbsolutePath());
        boolean create_judge = absolute_dir.mkdirs();
//        File parent_dir = new File(direction.getParent());
//        System.out.println(Arrays.toString(parent_dir.list()));
        File parent_file = new File(direction.getParent());
        System.out.println(Arrays.toString(parent_file.listFiles()));
    }
    public static void walkFile(File file){
        if (file.isFile()){
            System.out.println(file.getAbsolutePath());
        }else {
            System.out.println(file.getAbsolutePath()+"is direction");
            File[] files = file.listFiles();
            if(files!=null&&files.length>0){
                for (File file1 : files) {
                    walkFile(file1);
                }
            }
        }
    }
}

Stream

  • 輸入流:位元組(8bit)InputStream 字元(16bit)Reader
  • 輸出流:位元組(8bit)OutputStream 字元(16bbit)Writer
package com.learn.java_final;

import com.sun.org.apache.xml.internal.resolver.readers.ExtendedXMLCatalogReader;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Arrays;
// 注意一般使用InputSteam作為超類,FileInputStream作為子類進行檔案讀寫,利用StringBuffer將read讀取到的數字陣列轉為字串進行拼接
public class tt_stream {
    public static void main(String[] args) throws Exception {
        String content;
//        try (InputStream inputStream = new FileInputStream("D:\\Node.js\\新建資料夾\\新建文字文件.txt");) {
//            content = readAsString(inputStream);
//        }
//        System.out.println(content);
        out_read();
    }

    public static String readAsString(InputStream inputStream) throws Exception {
        int n;
        StringBuilder stringBuffer = new StringBuilder();
        while ((n = inputStream.read()) != -1) {
            stringBuffer.append((char) n);
        }
        return stringBuffer.toString();
    }

    public static void out_read() throws Exception {
//        byte[] buffer = new byte[100];
        byte[] bytes = {10, 4, 10, 30};
        try (InputStream input = new ByteArrayInputStream(bytes)){
            int n;
            while ((n=input.read())!=-1){
                System.out.print((char) n);
            }
        }
    }
}
OutputStream
public static void writeSome() throws Exception {
try (OutputStream outputStream = new FileOutputStream("readme.txt")) {
    // outputStream只能接受byte
	outputStream.write("hello".getBytes(StandardCharsets.UTF_8));
    // outputStream.flush() 將緩衝區的資料刷寫到檔案裡
	}
}

注意,對輸入輸出流進行filter時,所有的型別均向上轉型為InputStream,是為了控制子類爆炸的情況出現

也可以自定義FilterInputStream

public class learnStream {
    public static void main(String[] args) throws Exception {
        byte[] data = "hello.world".getBytes(StandardCharsets.UTF_8);
        try(CountInputStream inputStream = new CountInputStream(new ByteArrayInputStream(data))){
            int n;
            while ((n=inputStream.read())!=-1){
                System.out.println((char) n);
            }
            System.out.println(inputStream.getBytesRead());
        }
    }
}

class CountInputStream extends FilterInputStream {
    private int count = 0;
    protected CountInputStream(InputStream in) {
        super(in);
    }
    public int getBytesRead() {
        return this.count;
    }
    public int read() throws IOException {
        int n = in.read();
        if (n != -1) {
            this.count++;
        }
        return n;
    }
    public int read(byte[] b, int off, int len) throws IOException {
        int n = in.read(b, off, len);
        this.count += n;
        return n;
    }
}

位元組流

注意:無對應檔案時會報錯,寫入檔案會全覆蓋

public class copyFile {
    public static void main(String[] args) throws FileNotFoundException {
        String content = testFileReader("xx");
        System.out.println(content);
        testFileWriter(content,"readme.txt");
    }
    public static String testFileReader(String inPath){
        StringBuilder stringBuilder = new StringBuilder();
        try(FileReader fr = new FileReader(inPath);){
            // 臨時儲存資料的字元陣列
            char[] c = new char[1000];
            int len = 0;

            while ((len=fr.read(c))!=-1){
                stringBuilder.append(new String(c, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
    }
    public static void testFileWriter(String text,String outPath){
        try {
            FileWriter fw = new FileWriter(outPath);
            fw.write(text);
            fw.flush();
            fw.close();
        }catch (Exception e){
            e.printStackTrace();;
        }
    }
    public static void transferFile(String inPath,String outPath){
        try{
            FileReader fileReader = new FileReader(inPath);
            FileWriter fileWriter = new FileWriter(outPath);
            char[] chars = new char[100];
            int len = 0;
            while ((len = fileReader.read(c))!=-1){
                fileWriter.write(c,0,len);
            }
            fileWriter.flush();
            fileWriter.close();
            fileReader.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

緩衝流

FileInputStream,FileOutPutStream,FileReader,FileWriter操作較慢,收到磁碟的制約

因此出現了對應的BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter

public class learnBufferFile {
    public static void main(String[] args) {
        try {
//            testBufferedInputStream();
//            testBufferedOutputStream();
            copyFile();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 注意緩衝區大小,太小可能會出現亂碼
    public static void testBufferedInputStream() throws Exception {
        InputStream in = new FileInputStream("D:\\\\Node.js\\\\新建資料夾\\\\新建文字文件.txt");
        BufferedInputStream br = new BufferedInputStream(in);
        byte[] bytes = new byte[100];
        int len = 0;
        StringBuilder stringBuilder = new StringBuilder();
        while ((len = br.read(bytes)) != -1) {
            stringBuilder.append(new String(bytes, 0, len));
        }
        System.out.println(stringBuilder.toString());
        // 先開後關,棧型操作
        br.close();
        in.close();
    }
    public static void testBufferedOutputStream() throws IOException {
        OutputStream out = new FileOutputStream("readme1.txt");
        BufferedOutputStream bo = new BufferedOutputStream(out);
        String s = "hello world";
        bo.write(s.getBytes());
        bo.flush();
        bo.close();
        out.close();
    }
    // 緩衝字元流來複制檔案,注意緩衝區大小,太小可能會出現重複
    public static void copyFile() throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("D:\\\\Node.js\\\\新建資料夾\\\\新建文字文件.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("readme1.txt"));
        char[] c = new char[20];
        int len = 0;
        StringBuffer stringBuffer = new StringBuffer();
        while ((len = br.read(c))!=-1){
            stringBuffer.append(c);
        }
        bw.write(stringBuffer.toString());
        bw.flush();
        bw.close();
        br.close();
    }
}

轉換流

InputStreamReader in = new InputStreamReader(new FileInputStream("xx"),"GBK");

OutStreamWriter os = new OutputStreamWriter(new FileOutputStream("xx"),"GBK");

通過轉換流與BufferedReader與PrintWriter進行讀寫

public class LearnFile {
    private static final File f = new File("." + File.separator + "testFile.txt");
    private static final Scanner SCANNER = new Scanner(System.in);
    public static void main(String[] args) throws IOException {
        File target_file = createFile();
        System.out.println("write first");
        line_write(target_file);
        System.out.println("then read");
        line_read(target_file);
    }
    public static File createFile() throws IOException {
        if (f.isFile()) {
            System.out.println("file already exist,and to delete it");
        } else {
            System.out.println(f.createNewFile());
        }
        return f;
    }
    public static void line_read(File file1) {
        try (InputStream inputStream = new FileInputStream(file1);
             InputStreamReader inputStreamReader = new InputStreamReader(inputStream,StandardCharsets.UTF_8);
             BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        ) {
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void line_write(File file2) {
        try (OutputStream outputStream = new FileOutputStream(file2);
             OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
             PrintWriter printWriter = new PrintWriter(outputStreamWriter);
        ) {
            while (true) {
                String line_write = SCANNER.nextLine().trim();
                if (line_write.trim().isEmpty()) {
                    System.out.println("end input");
                    break;
                } else {
                    printWriter.println(line_write);
                    printWriter.flush();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}