Java中的IO流详解(进阶五)

目录

  • 友情提醒
  • 第一章、File类和IO技术概述
    • 1.1)File类和IO技术的作用
    • 1.2)创建File类对象
    • 1.3)File类中的方法
    • 1.4)文件过滤器:FileFileter
  • 第二章、IO流
    • 2.1)IO流的分类
    • 2.2)字节输入流:InputStream
      • 2.2.1)操作文件的字节输入流:FileInputStream
      • 2.2.2)字节缓冲输入流:BufferedInputStream(高效)
    • 2.3)字节输出流:OutputStream
      • 2.3.1) 操作文件的字节输出流:FileOutputStream
      • 2.3.2)字节缓冲输出流:BufferedOutputStream(高效)
      • 2.3.3)字节打印流:PrintStream
    • 2.4)字符输入流:Reader
      • 2.4.1)操作文件的字符输入流:FileReader
    • 2.5)字符输出流:Writer
      • 2.5.1)操作文件的字符输出流:FileWriter
      • 2.5.2)字符打印流:PrintWriter
  • 第三章、转换流
    • 3.1)字符编码表
    • 3.2)字符流通向字节流:OutputStreamWriter(编码)
    • 3.3)字节流通向字符流:InputStreamReader(解码)
  • 第四章、序列化流与反序列化流
    • 4.1)对象序列化流:ObjectOutputStream
    • 4.2)对象反序列化流:ObjectInputStream
    • 4.3)序列化接口Serializable与瞬态关键字transient
  • 第五章、IO流案例
    • 5.1)复制单个文件
    • 5.2)使用缓冲字节流复制单个文件(高效)
    • 5.3)缓冲字节流复制当前目录下所有文件·
    • 5.4)切割文件/合并文件

友情提醒

先看文章目录,大致了解知识点结构,直接点击文章目录可以跳转到文章指定位置。

第一章、File类和IO技术概述

1.1)File类和IO技术的作用

1.File类
①File类简介:Java把现实存在的文件和目录路径名描述成一个File类类。
②File类只是对持久设备上的文件和文件夹进行操作。不能去操作文件中的数据。要操作数据需要使用IO技术。
2.IO技术
①IO技术专门来实现数据与持久设备(持久保存数据的设备。硬盘、U盘等)间的交互。
②主要功能:程序中的数据可以保存到持久设备中,或者从持久设备中把数据读取到我们的Java程序中。
③I:Input:输入或者读取,持久设备数据输入到内存中。
O:Output:输出或者写出,内存中的数据输出到持久设备。

1.2)创建File类对象

①public File(String pathname) 根据文件或文件夹的路径名创建一个File对象。
②public File(String parent,String child) 根据父目录的路径名和子文件名创建一个File对象。
③public File(File parent,String child) 根据父目录的File对象和子文件名创建一个File对象。

 public static  void  test1(){
        //通过构造方法实例化File对象,jvm不会去验证参数位置定义的路径资源是否真实存在;
        File f1 = new File("E\\2023Java\\Test\\file.txt");
        File f2 = new File("E\\2023Java\\Test", "test1.txt");

        File f3 = new File("E\\2023Java\\Test");
        File f4 = new File(f3, "test2.txt");
        File f5 = new File("1.txt");

System.out.println(f1);//E\2023Java\Test\file.txt
System.out.println(f2);//E\2023Java\Test\test1.txt
System.out.println(f3);//E\2023Java\Test
System.out.println(f4);//E\2023Java\Test\test2.txt
System.out.println(f5);//1.txt
    }

1.3)File类中的方法

①get方法

 public static void test2(){

        File f1 = new File("hello\\2.txt");
//String getName():获取最后一个路径名字或者文件名字的字符串
//String getPath():获取路径名字字符串
System.out.println(f1.getName());//2.txt
System.out.println(f1.getPath());//hello\2.txt
        
//String getAbsolutePath():获取绝对路径名字符串。
//File getAbsoluteFile():获取绝对路径名形式。
System.out.println(f1.getAbsolutePath());//E:\javase\hello\2.txt
System.out.println(f1.getAbsoluteFile()); //E:\javase\hello\2.txt

//String getParent():返回父目录的路径名字符串;如果没有指定父目录,则返回 null。
//File getParentFile():返回父目录的路径名形式;如果没有指定父目录,则返回 null。
        System.out.println(f1.getParent());//hello
        System.out.println(f1.getParentFile());//hello
    }

②创建文件夹和文件的方法

  public  static void test3(){
//创建目录:boolean mkdir():当不存在具有此抽象路径名时,创建此抽象路径名指定的目录
//在E盘下创建test目录
        File f1 = new File("E:\\test");
        boolean b = f1.mkdir();
        System.out.println(b);
//boolean mkdirs():当不存在具有此抽象路径名时,创建此抽象路径名指定的目录,包括所有的父目录。
//在E盘下创建test\\bbb\\ccc目录
        File f2 = new File("E:\\test1\\aaa\\bbb");
        boolean b1 = f2.mkdirs();
        System.out.println(b1);
        System.out.println("**************************");

//创建文件:boolean createNewFile():当不存在具有此抽象路径名指定名称的文件时,创建
//在E:\test下创建woshisb.txt文件
        try {
            File f3 = new File("E:\\test\\woshisb.txt");
            boolean b2 = f3.createNewFile();
            System.out.println(b2);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

③删除文件和文件夹
delete方法可以删除目录,也可以删除文件
这种删除不会进回收站

 public static void test4(){
        //因为test文件夹里有文件woshisb.txt,所以删除失败
        File f1 = new File("E:\\test");
        boolean b1 = f1.delete();
        System.out.println(b1);

        //delete方法不支持多层级同时删除,所以只删除了bbb文件夹
        File f2 = new File("E:\\test1\\aaa\\bbb");
        boolean b2 = f2.delete();
        System.out.println(b2);

        //因为不存在所以无法删除,返回false
        File f3 = new File("E:\\aaa");
        boolean b3 = f3.delete();
        System.out.println(b3);//false
    }

④判断是否是文件/路径

  public static void test5() {
        /*判断
          boolean isAbsolute():测试此抽象路径名是否为绝对路径名。
          boolean isDirectory():测试此抽象路径名表示的文件是否是一个目录。
          boolean isFile():测试此抽象路径名表示的文件是否是一个标准文件。
          boolean isHidden():测试此抽象路径名指定的文件是否是一个隐藏文件。
          boolean exists():测试此抽象路径名表示的文件或目录是否存在。 */

//        File f = new File("E:\\woshisb.txt");
        File f = new File("E:\\test");
        System.out.println(f.isAbsolute());
        System.out.println(f.isDirectory());
        System.out.println(f.isFile());
        System.out.println(f.isHidden());
        System.out.println(f.exists());
    }

⑤列举文件和目录

 public static void test6() {
 //String[] list():返回一个字符串数组,表示的目录中的文件和目录。
        File file = new File("E:\\test");
        String[] strs = file.list();
        for (String str : strs) {
            System.out.println(str);
        }

        System.out.println("******************************");
 //File[] listFiles():返回一个抽象路径名数组,表示目录和其中的文件。
        File[] files = file.listFiles();
        for (File f : files) {
            System.out.println(f);
        }
    }

1.4)文件过滤器:FileFileter

①作用:过滤我们不需要的文件,File[] listFiles(FileFilter filter) 返回符合过滤器条件的元素组成的数组。
②自定义文件过滤器类,实现FileFilter 接口,重写accept方法,并定义过滤规则
③调用listFiles方法的时候,会把每个元素都拿来调用accept方法,符合就返回true添加到数组中,否则返回false不添加到数组;

public class MyFilter2 implements FileFilter {
    private String suffix;
    public MyFilter2(String suffix) { this.suffix = suffix; }
    public MyFilter2() { }
    public String getSuffix() { return suffix; }
    public void setSuffix(String suffix) { this.suffix = suffix; }
    @Override
    public boolean accept(File file) {
   System.out.println("过滤器是文件并以.xxx结尾就不过滤,xxx自己决定");
        boolean b1 = file.isFile();
        boolean b2 = file.toString().endsWith(suffix);
        return b1 && b2;
    }
}

测试文件过滤器

public class TestFileFilter {
    public static void main(String[] args) {
        test1();    }
    public static void test1() {
        //得到E:\\test下所有.xxx结尾的文件,xxx自己决定
        File file = new File("E:\\test");

        //1、得到所有.txt结尾的文件,展示
        MyFilter2 myFilter2 = new MyFilter2(".txt");
        File[] files = file.listFiles(myFilter);

        for (File f : files) {
            System.out.println(f);
/*过滤器是文件并以.xxx结尾就不过滤,xxx自己决定
过滤器是文件并以.xxx结尾就不过滤,xxx自己决定
过滤器是文件并以.xxx结尾就不过滤,xxx自己决定
过滤器是文件并以.xxx结尾就不过滤,xxx自己决定
E:\test\2.txt
*/
        }
    }

第二章、IO流

2.1)IO流的分类

①数据传输过程中,一切数据的传输始终为二进制数据,最后存储形式都是字节(二进制数字)。
②字节(Byte)是计算机信息技术用于计量存储容量的一种计量单位,一个字节存储8位无符号数(即1字节=8bit),储存的数值范围为0-255。(255用二进制表示 = 11111111)
IO流的分类:IO流体系脑图链接
Java中的IO流详解(进阶五)_第1张图片

2.2)字节输入流:InputStream

①InputStream抽象类,是表示输入字节流所有类的超类。他们操作的数据都是字节,定义了输入字节流的基本共性功能方法

2.2.1)操作文件的字节输入流:FileInputStream

①读取文件中的数据时,调用read方法,实现从文件一次只能读取一个字节数据。

   public static void test1() throws IOException {
        //创建File对象,关联目标资源(文件)
        File file = new File("E:\\IO\\in.txt");
        //创建FileInputStream对象,绑定File对象
        FileInputStream fis = new FileInputStream(file);
        //每次读取一个字节内容
        int num = fis.read();
        System.out.println(num);
        System.out.println((char) num);
        num = fis.read();
        System.out.println(num);
        System.out.println((char) num);
        num = fis.read();
        System.out.println(num);
        System.out.println((char) num);
        num = fis.read();
        System.out.println(num);
        System.out.println((char) num);
      
        fis.close();
    }
//--------------------------分割----------------------------------
//使用循环读取数据
public static void test2() throws IOException {
        //创建File对象,关联目标资源(文件)
        File file = new File("E:\\IO\\in.txt");
        //创建FileInputStream对象,绑定File对象
        FileInputStream fis = new FileInputStream(file);
        //每次读取一个字节内容,使用循环来实现
        int num;
       while (true){
           if ((num=fis.read())==-1){
               break;
           }
           System.out.println((char)num);
       }
        fis.close();

②读取文件中的数据时,调用read的重载方法read(byte [ ])方法,实现从文件中一次读取多个字节数据到byte[]数组内部,减少和磁盘文件的交互次数,效率高。
文件内容是abcdefg

 public static void test3() throws IOException {
        //创建File对象,关联目标资源(文件)
        File file = new File("E:\\IO\\in.txt");//文件内容是abcdefg
        //创建FileInputStream对象,绑定File对象
        FileInputStream fis = new FileInputStream(file);

        //一次读取多个字节到byte[]数组内部,减少和磁盘文件的交互次数,效率高
        byte[] bs = new byte[5];
        //int read(byte[] bs):返回值是读取到的有效字节数5
        int len = fis.read(bs);
        System.out.println(len);                //这次read方法执行,得到的有效字节数为5
        System.out.println(new String(bs));     //内容为"abcde"
        System.out.println("=========================");

  //      len = fis.read(bs);
  //      System.out.println(len);                //这次read方法执行,得到的有效字节数为2
  //      System.out.println(new String(bs));     //"fgcde"将bs数组所有元素都转为String会存在上次读取内容

		// 把上面的注释了换一个String的构造方法:String(byte[] bytes, int offset, int length),从
        len = fis.read(bs);
        System.out.println(len);                //2
        //从0下标开始将后面len个字节转为string,这样就没重复内容
        System.out.println(new String(bs,0,len));//fg
        fis.close();
    }

③综合上述的代码,写最终版大招

public static void test4() throws IOException {
            //创建File对象,关联目标资源(文件)
            File file = new File("E:\\IO\\in.txt");
            //创建FileInputStream对象,绑定File对象
            FileInputStream fis = new FileInputStream(file);

            //一次读取1024字节内容到byte[]内部,之后进行读操作
            byte[] bs = new byte[1024];
            int len;        //用于记录读取到的有效字节数,读到文件末尾则返回-1
            while ((len = fis.read(bs)) != -1) {
            //从0下标开始将后面len个字节转为string,这样就没重复内容
                System.out.println(new String(bs,0,len));
            }
        fis.close();
    }

2.2.2)字节缓冲输入流:BufferedInputStream(高效)

①读取流中的数据,内部包含了一个缓冲区,通过缓冲区读写,提高了IO流的读写速度
②构造方法public BufferedInputStream(InputStream in)

private static void read() throws IOException {
		//1,创建缓冲流对象
		FileInputStream fileIn = new FileInputStream("abc.txt");
		//把基本的流包装成高效的流
		BufferedInputStream in = new BufferedInputStream(fileIn);
		//定义一个缓冲区
byte[] buf = new byte[1024];
		//2,读数据
		int len = 0;
		while ( (ch = in.read(buf)) != -1 ) {
			//打印
			System.out.print(new String(buf, 0, len));
		}
		//3,关闭
		in.close();
	}

2.3)字节输出流:OutputStream

①OutputStream抽象类是表示输出字节流所有类的超类。他们操作的数据都是字节,定义了输出字节流的基本共性功能方法

2.3.1) 操作文件的字节输出流:FileOutputStream

①输出流的覆盖模式:没文件会在目录下创建一个文件,有文件会覆盖内容

public static void test1() throws IOException {
        //创建文件字节输出流对象,关联File资源(定位文件位置)
        //E盘下没这个文件会在目录下创建一个文件,有文件会覆盖内容
        FileOutputStream fos = new FileOutputStream(new File("E:\\out666.txt"));
        fos.write(97);//a
        fos.write(98);//b
        fos.write(99);//c
        //\r是回车符,\n是换行符
       fos.write("\n\r加油".getBytes());//加油
        fos.close();
    }

②输出流的追加模式:没文件会在目录下创建一个文件,有追加模式不会覆盖原文件内容而是追加内容。

public static void test2() throws IOException {
        //创建文件字节输出流对象,关联File资源(定位文件位置),
        // 并且开启追加模式,追加模式不会覆盖原文件内容
        FileOutputStream fos = new FileOutputStream(new File("E:\\out2.txt"), true);

        fos.write("发福。\r\n".getBytes());
        fos.write("变胖。\r\n".getBytes());

        fos.close();
    }

2.3.2)字节缓冲输出流:BufferedOutputStream(高效)

①写入数据到流中,内部包含了一个缓冲区,通过缓冲区读写,提高了IO流的读写速度
②构造方法public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流。

public class BufferedOutputStreamDemo01 {
	public static void main(String[] args) throws IOException {
		write();
	}

	private static void write() throws IOException {
		//创建基本的字节输出流
		FileOutputStream fileOut = new FileOutputStream("abc.txt");
		//使用高效的流,把基本的流进行封装,实现速度的提升
		BufferedOutputStream out = new BufferedOutputStream(fileOut);
		//2,写数据
		out.write("hello".getBytes());
		//3,关闭流
		out.close();
	}
}

2.3.3)字节打印流:PrintStream

2.4)字符输入流:Reader

①使用字节流去读取文本文件可能由于编码问题,每个中文所占用的字节数不同。如:gbk下的中文2字节,utf-8下的中文占用3字节。
②字符流只能操作字符,无法操作其他数据,如声音、视频

2.4.1)操作文件的字符输入流:FileReader

FileReader类自身没有方法,使用的都是父类中的方法。

public static void test() throws IOException {
        //创建文件字符输入流对象,关联数据源
        FileReader fr = new FileReader("io.txt");
        char[] cs = new char[4];
        int len;        //记录读取到的有效字符数
        while ((len = fr.read(cs)) != -1) {
            System.out.println(new String(cs,0,len));
        }
        fr.close();
    }

2.5)字符输出流:Writer

2.5.1)操作文件的字符输出流:FileWriter

FileWriter类自身没有方法,使用的都是父类中的方法。
①覆盖原文件内容

 public static void test1() throws IOException {
        //创建文件字符输出流对象,绑定数据目的
        FileWriter fw = new FileWriter("out.txt");
        fw.write("自己好,");
        fw.write("\r\n不是真的好!");

//        fw.flush();
        fw.close();
    }

②不覆盖原文件内容,追加数据

 public static void test2() throws IOException {
        //创建文件字符输出流对象,绑定数据目的
        FileWriter fw = new FileWriter("out.txt", true);
        Scanner input = new Scanner(System.in);
        for (int i = 1;i <= 3;i++) {
            System.out.println("请输入一串数据:");
            String content = input.next();
            fw.write(content + "\r\n");
            fw.flush();
        }
        fw.close();
    }

2.5.2)字符打印流:PrintWriter

第三章、转换流

3.1)字符编码表

①字符编码表:就是现实中的字符数据和计算机二进制的对应关系表。
②编码:字符—>(数字),解码:(数字)—>文字
③常用的编码表:

ASCII1、英文字符、数字与二进制数据的一一对应关系
2、一个英文字符对应1Bytes,1Bytes=8bit,8bit最多包含256个数
字,所以一共最多对应256个字符。
GBK1、中文字符、英文字符、数字与二进制数的 一一对应关系
2、一个英文字符对应1Bytes
   一个中文字符对应2Bytes   
   2Bytes=16bit,16bit最多包含65536个数字,一共对应65536个字符
unicode表
国际标准码表:无论是什么文字,都用两个字节存储。

3.2)字符流通向字节流:OutputStreamWriter(编码)

OutputStreamWriter流可使用指定的字符编码表,将要写入流中的字符按照指定的编码表转成字节,在使用字节流将这些字节写出去。

   public static void test2() throws IOException {
//   指定设置为utf-8的字符编码表
//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("out6.txt"),"utf8");

   //指定设置为gbk编码的字符编码表
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("out6.txt"),"gbk");
        osw.write("今天要下雨!\r\n");
        osw.write("大家带伞了吗?\r\n");
        osw.close();
    }

    public static void test1() throws IOException {
    //使用平台默认字符编码表
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("out5.txt"));
        osw.write("今天要下雨!\r\n");
        osw.write("大家带伞了吗?\r\n");
        osw.close();
    }

3.3)字节流通向字符流:InputStreamReader(解码)

InputStreamReader:使用指定的字符编码表读取字节并将其解码为字符。
在读取指定的编码的文件时,一定要指定编码格式,否则就会发生解码错误,而发生乱码现象。

    public static void test2() throws IOException {
    //FileInputStream放入InputStreamReader使用gbk编码表解码为字符
    再放入BufferedReader使用readLine方法
BufferedReader br = new BufferedReader(new InputStre
amReader(new FileInputStream("E:\\IO\\change\\change.txt"), "gbk"));
        String line = br.readLine();
        System.out.println(line);
        br.close();

    }

    public static void test1() throws IOException {
//使用默认的编码表解码为字符
FileReader fr = new FileReader(new File("E:\\IO\\change\\change.txt"));
        char[] cs = new char[10];
        int len;
        while ((len = fr.read(cs)) != -1) {
            System.out.println(new String(cs,0,len));
        }
        fr.close();
    }

第四章、序列化流与反序列化流

4.1)对象序列化流:ObjectOutputStream

4.2)对象反序列化流:ObjectInputStream

4.3)序列化接口Serializable与瞬态关键字transient

第五章、IO流案例

5.1)复制单个文件

将文件中的内容读取输入到程序,再从程序输出到另一个同名文件
①复制单个文件:

  //copy任意的文件
    public static void copyFile2(String src, String dest) throws IOException {
        long start = System.currentTimeMillis();
        //创建文件字节输入、输出流,分别绑定数据源和数据目的
        FileInputStream fis = new FileInputStream(src);
        FileOutputStream fos = new FileOutputStream(dest);

        byte[] bs = new byte[1024];
        int len;
        while ((len = fis.read(bs)) != -1) {
            fos.write(bs, 0, len);
        }
        //后开启的先关闭
        fos.close();
        fis.close();

        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

5.2)使用缓冲字节流复制单个文件(高效)

①复制单个文件

 public static void copyFile3(String src, String dest) throws IOException {
        long start = System.currentTimeMillis();
        //创建节点流(文件字节输入、输出流),分别绑定数据源和数据目的
        FileInputStream fis = new FileInputStream(src);
        FileOutputStream fos = new FileOutputStream(dest);
        //创建处理流(缓冲字节输入、输出流),分别绑定节点流对象
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        byte[] bs = new byte[1024];
        int len;
        while ((len = bis.read(bs)) != -1) {
            bos.write(bs, 0, len);
        }
        //关闭处理流的过程中,会自动触发关闭所包含的节点流
        bos.close();
        bis.close();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

5.3)缓冲字节流复制当前目录下所有文件·

①复制当前目录层级下所有文件

/*①判断目标目录是否存在,如果不存在就立即创建
  ②得到src资源下所有的内容(文件、目录) ==> File[] listFile()
  ③遍历File数组元素,判断是否文件 ==> boolean isFile()
  ④在遍历的过程中发现是文件,则将文件进行copy操作,copy后的文件的名字和源文件名字保持一致
  提示:获取源文件名字的方法 ==> String getName()*/
public class CopyFile{
    public static void main(String[] args) throws IOException {
        copyFile(new File("E:\\IO\\image"), new File("E:\\IO\\copy"));
    }

    public static void copyFile(File src,File dest) throws IOException {
        //判断目标目录dest是否真实存在
        if (!dest.isDirectory()) {
            //说明不存在,直接创建
            dest.mkdir();
        }

        //得到src资源下所有的内容(文件、目录)
        File[] files = src.listFiles();
        //遍历数组元素
        for (File file : files) {
            //判断是否是文件
            if (file.isFile()) {
                //说明是文件,进行复制操作,获得文件的名字
                String name = file.getName();
                //获得文件的绝对路径
                String path = file.getAbsolutePath();
//创建FileInputStream对象,根据path绑定(目标资源),把FileInputStream对象放入BufferedInputStream
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
//FileOutputStream对象,根据dest和name绑定目标资源,把FileOutputStream对象放入BufferedOutputStream
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(dest, name)));

                byte[] bs = new byte[1024];
                int len;
                while ((len = bis.read(bs)) != - 1) {
                    bos.write(bs, 0, len);
                }
                bos.close();
                bis.close();
            }
        }
    }
}

5.4)切割文件/合并文件

①切割文件

public class TestCut {
    public static void main(String[] args) throws IOException {
        //创建输入流对象,关联绑定需要被切割文件
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\IO\\image\\3.avi"));
        //5M大小切割
        byte[] bs = new byte[1024 * 1024 * 5];
        int len;
        int name = 1;       //用于给碎片文件起名字
        while ((len = bis.read(bs)) != -1) {
            //创建输出流对象,关联绑定当前的碎片文件
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\io\\cut\\" + name + ".avi"));
            bos.write(bs, 0, len);
            bos.close();
            name++;
        }

        bis.close();
    }
}

②合并文件

public class TestMerge {
    public static void main(String[] args) throws IOException {
        //创建输出流对象,绑定需要被合并成的文件,没有这个文件会直接创建
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\IO\\merge\\合并.avi"));
        byte[] bs = new byte[1024];
        int len;

        for (int i = 1;i <= 11;i++) {
            //创建输入流对象,绑定当前的碎片文件
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\io\\cut\\" + i + ".avi"));
            while ((len = bis.read(bs)) != -1) {
                bos.write(bs, 0, len);
            }
            bis.close();
        }

        bos.close();
    }
}

你可能感兴趣的:(Java基础知识汇总,java,python,开发语言)