Java进阶学习

一、IO框架学习

img

1.流的概念

内存与存储设备之间传输数据的通道

2.流的分类

按方向【重点】

  • 输入流:将<存储设备>中的内容读到<内存>中
  • 输出流:将<内存>中的内容写到<存储设备>中

按单位

  • 字节流:以字节为单位,可以读写所有数据
  • 字符流:以字符为单位,只能读写文本数据

按功能

  • 节点流:具有实际传输数据的读写功能
  • 过滤流:在节点流的基础之上增强功能

3.字节流

字节流的父类(抽象类)

// InputStream 字节输入流
public int read(){}
public int read(byte[] b){}
public int read(byte[] b, int off, int len){}

// OutputStream 字节输出流
public void write(int n){}
public void write(byte[] b){}
public void write(byte[] b, int off, int len){}

文件字节流

文件输入流

image-20210206200455088

image-20210206201009753

package IO.byteStream;

import com.sun.org.apache.bcel.internal.generic.NEW;

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

//字节输入流

public class Demo01 {
    public static void main(String[] args) throws IOException {
        // 1 创建FileInputStream 并指定文件路径
        FileInputStream fileInputStream = new FileInputStream("e://a.txt");
        //2.读取文件 返回-1证明读取完毕
        //int a=fileInputStream.read();
        //System.out.println(a);
        //3.循环读取 单字节读取!
        //int data=0;
        //while ((data=fileInputStream.read())!=-1){
        //    System.out.println((char) data);
        //}
        //4.多字节读取
        //每次读取3个字节

        /*
        byte[] str=new byte[3];
        int read = fileInputStream.read(str);
        System.out.println("实际读取的个数:"+read);
        System.out.println(new String(str));
        int read02 = fileInputStream.read(str);
        System.out.println("实际读取的个数:"+read02);
        System.out.println(new String(str));
         */
        int count=0;
        byte[] buff = new byte[4];
        while ((count=fileInputStream.read(buff))!=-1){
            System.out.println(new String(buff,0,count));
        }
        fileInputStream.close();
    }
}

image-20210206112821062

拓展:new String()

new String(byte bytes[], int offset, int length) 

image-20210206112911463

image-20210206112950183

文件输出流

image-20210206200844885

image-20210206200932808

package IO.byteStream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class Demo02 {
    public static void main(String[] args) throws IOException {
        // 1 创建文件字节输出流
        FileOutputStream fileOutputStream = new FileOutputStream("e://b.txt",true); // true表示不覆盖 接着写 默认为 false
        // 2 写入文件
        fileOutputStream.write(97);
        fileOutputStream.write('c');
        fileOutputStream.write('c');
        fileOutputStream.write('\n');
        // 3 写入字符串
        String str = new String("helloworld");
        fileOutputStream.write(str.getBytes(StandardCharsets.UTF_8));

        fileOutputStream.close();
        System.out.println("执行完毕!");
    }
}

image-20210206114129823

图片复制案例

package IO.byteStream;

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

public class Demo03 {
    public static void main(String[] args) throws IOException {
        // 1 创建流
        // 1.1 文件字节输入流
        FileInputStream fileInputStream = new FileInputStream("e://a.jpg");
        // 1.2 文件字节输出流
        FileOutputStream fileOutputStream = new FileOutputStream("e://b.jpg");
        // 2 边读边写
        byte[] bytes = new byte[1024];
        int count=0;
        while ((count=fileInputStream.read(bytes))!=-1){
            fileOutputStream.write(bytes,0,count);
        }
        // 3 关闭
        fileOutputStream.close();
        fileInputStream.close();
        System.out.println("执行完毕!");
    }
}

image-20210206120047874

字节缓冲流

缓冲流:BufferedInputStream/ BufferedOutputStream

  • 提高IO效率,减少访问磁盘次数
  • 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close

image-20210206201233858

image-20210206201317560

package IO.BufferedStream;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Demo01 {
    // 使用字节缓冲流 读取 文件
    public static void main(String[] args) throws IOException {
        // 1 创建BufferedInputStream
        FileInputStream fileInputStream = new FileInputStream("e://a.txt");
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        // 2 使用字节缓冲流读取
        /*
        int data= 0;
        while ((data=bufferedInputStream.read())!=-1){
            System.out.print((char) data);
        }
        System.out.println();
         */
        // 3 自己写一个缓冲区
        byte[] bytes = new byte[1024];
        int count = 0;
        while ((count=fileInputStream.read(bytes))!=-1){
            System.out.println(new String(bytes,0,count));
        }
        // 4 只需要关闭缓冲流即可!
        bufferedInputStream.close();
        fileInputStream.close();
    }
}

image-20210206121338879

image-20210206201425306

image-20210206201444489

package IO.BufferedStream;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class Demo02 {
    // 使用字节缓冲流 写入 文件
    public static void main(String[] args) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("e://c.txt",false);
        // 1 创建BufferedInputStream
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
        String str = new String("helloworld");
        // 2 写入文件
        bufferedOutputStream.write(str.getBytes(StandardCharsets.UTF_8));// 写入8k缓冲区
        bufferedOutputStream.flush();//刷新到硬盘
        // 3 关闭缓冲流
        bufferedOutputStream.close();
        System.out.println("进程完成");
    }
}

image-20210206130104830

4.对象流

ObjectOutputStream / ObjectInputStream
  • 增强了缓冲区功能
  • 增强了读写8种基本数据类型和字符串的功能
  • 增强了读写对象的功能
    • readObject() 从流中读取一个对象
    • writeObject(Object obj) 向流中写入一个对象

使用流传输对象的过程称为序列化、反序列化

ObjectOutputStream

image-20210206202227118

ObjectOutputStream将Java对象的原始数据类型和图形写入OutputStream。可以使用ObjectInputStream读取(重构)对象。可以通过使用流的文件来实现对象的持久存储。如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。

只有支持java.io.Serializable接口的对象才能写入流中。 每个可序列化对象的类被编码,包括类的类名和签名,对象的字段和数组的值以及从初始对象引用的任何其他对象的关闭。

方法writeObject用于将一个对象写入流中。 任何对象,包括字符串和数组,都是用writeObject编写的。 多个对象或原语可以写入流。 必须从对应的ObjectInputstream读取对象,其类型和写入次序相同。

序列化

package IO.objectStream;
//ObjectStream序列化
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Demo01 {
    public static void main(String[] args) throws IOException {
        // 1 创建文件输出流
        FileOutputStream fileOutputStream = new FileOutputStream("e://stu.bin");
        // 2 创建对象输出流
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        // 3 序列化
        Student stu01 = new Student("张三", 18);
        Student stu02 = new Student("李四", 18);
        objectOutputStream.writeObject(stu01);
        objectOutputStream.writeObject(stu02);
        // 4 刷新
        objectOutputStream.flush();
        // 5 关闭
        objectOutputStream.close();
        System.out.println("序列化完毕!");
    }
}

image-20210206143558626

//Student类需要实现 Serializable 接口 这个接口仅仅标识这个类可以实现序列化
public interface Serializable {
}
//Student类
package IO.objectStream;

import java.io.Serializable;

public class Student implements Serializable {
    private String name;
    private  int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = 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;
    }

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

image-20210206144026110

ObjectInputStream

image-20210206202142434

ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象。

ObjectOutputStream和ObjectInputStream可以分别为与FileOutputStream和FileInputStream一起使用的对象图提供持久性存储的应用程序。 ObjectInputStream用于恢复先前序列化的对象。 其他用途包括使用套接字流在主机之间传递对象,或者在远程通信系统中进行封送和解组参数和参数。

ObjectInputStream确保从流中创建的图中的所有对象的类型与Java虚拟机中存在的类匹配。 根据需要使用标准机制加载类。

只能从流中读取支持java.io.Serializable或java.io.Externalizable接口的对象。

反序列化

package IO.objectStream;

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

public class Demo02 {
    // 使用ObjectInputSteam实现反序列化(读取重构对象)
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 1 创建文件输入流
        FileInputStream fileInputStream = new FileInputStream("e://stu.bin");
        // 2 创建对象流
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        // 3 读取文件(反序列化)
        Student student01 = (Student) objectInputStream.readObject();
        Student student02 = (Student) objectInputStream.readObject();
        // 4 关闭
        objectInputStream.close();
        System.out.println("执行完毕!");
        // 5 输出
        System.out.println(student01.toString());
        System.out.println(student02.toString());
    }
}

Serializable 接口

类的序列化由实现java.io.Serializable接口的类启用。 不实现此接口的类将不会使任何状态序列化或反序列化。 可序列化类的所有子类型都是可序列化的。 序列化接口没有方法或字段,仅用于标识可串行化的语义。

注意事项

  1. 某个类要想序列化必须实现 Serializable接口
  2. 序列化类中对象属性要求实现 Serializable接口
  3. 序列化版本号ID,保证序列化的类和反序列化的类是同一个类
  4. 使用transient修饰属性,这个属性就不能序列化
  5. 静态属性不能序列化
  6. 序列化多个对象,可以借助集合来实现
package IO.objectStream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

public class Demo03 {
    public static void main(String[] args) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("e://bai.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        Student student = new Student("王麻子", 56);
        Student student1 = new Student("王二", 96);
        ArrayList<Student> students = new ArrayList<>();
        students.add(student);
        students.add(student1);
        objectOutputStream.writeObject(students);
        objectOutputStream.close();
    }
}

image-20210206152312381

package IO.objectStream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;

public class Demo04 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        FileInputStream fileInputStream = new FileInputStream("e://bai.txt");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        ArrayList arrayList = (ArrayList) objectInputStream.readObject();
        System.out.println(arrayList);
        objectInputStream.close();
    }
}

image-20210206152234980

5.编码方式

常见编码

  • ASCII 码

    • 学过计算机的人都知道 ASCII 码,总共有 128 个,用一个字节的低 7 位表示,0~31 是控制字符如换行回车删除等;32~126 是打印字符,可以通过键盘输入并且能够显示出来。 
  • GBK(扩展GB2312)

    • 全称叫《汉字内码扩展规范》,是国家技术监督局为 windows95 所制定的新的汉字内码规范,它的出现是为了扩展 GB2312,加入更多的汉字,它的编码范围是 8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。  
  • GB18030(兼容GB2312)

    • 全称是《信息交换用汉字编码字符集》,是我国的强制标准,它可能是单字节、双字节或者四字节编码,它的编码与 GB2312 编码兼容,这个虽然是国家标准,但是实际应用系统中使用的并不广泛。  
  • Unicode编码集

    • UTF-8
      • UTF-16 统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量,而且也没必要。而 UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以是由 1~6 个字节组成。
      • UTF-8 有以下编码规则:
        1. 如果一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。可见,所有 ASCII 编码已经是 UTF-8 了。
        2. 如果一个字节,以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
        3. 如果一个字节,以 10 开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节

Reader类

Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理读取字节到字符的转换,而具体字节到字符的解码实现它由 StreamDecoder 去实现,在 StreamDecoder 解码过程中必须由用户指定 Charset 编码格式。值得注意的是如果你没有指定 Charset,将使用本地环境中的默认字符集,例如在中文环境中将使用 GBK 编码。

img

Writer类

字符的父类是 Writer,字节的父类是 OutputStream,通过 OutputStreamWriter 转换字符到字节。如下图所示:

img

6.字符流

问题引入

package IO.charStream;

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

public class Demo01 {
    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream = new FileInputStream("e://baixiao.txt");

        int data=0;
        while ((data=fileInputStream.read())!=-1){
            System.out.print((char)data);  //2个字 6个字节
        }

        fileInputStream.close();
    }
}

image-20210206153512107

字符流的父类(抽象类)

reader 字符输入流

  • public int read(){}
  • public int read(char[] c){}
  • public int read(char[] b, int off, int len){}

Writer 字符输出流

  • public void write(int n){}
  • public void write(String str){}
  • public void write(char[] c){}

FileReader

image-20210206202729823

package IO.charStream;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Demo02 {
    public static void main(String[] args) throws IOException {
        // 1 创建FileReader 文件字符输入流
        FileReader fileReader = new FileReader("e://baixiao.txt");
        // 2 单个字符读取
        /*
        int data=0;
        while ((data=fileReader.read())!=-1){
            System.out.println((char) data);// 读取一个字符
            System.out.println(data);
        }
         */
        // 3 创建字符缓冲区读取
        char[] chars = new char[2];
        int data=0;
        while ((data=fileReader.read(chars))!=-1){
            System.out.println(new String(chars, 0, data));
        }
        // 4 关闭
        fileReader.close();
    }
}

image-20210206155532912

FileWriter

image-20210206202922983

package IO.charStream;

import java.io.FileWriter;
import java.io.IOException;

public class Demo03 {
    public static void main(String[] args) throws IOException {
        FileWriter fileWriter = new FileWriter("e://hahah.txt");
        String str="Java是世界上最好的语言!";
        for (int i=0;i<5;i++) {
            fileWriter.write(str);
        }
        fileWriter.close();
        System.out.println("执行完毕!");
    }
}

image-20210206160023430

进行文本文件复制

不能复制图片或二进制文件(声音图片),但是使用字节流可以复制任意文件

package IO.charStream;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo04 {
    public static void main(String[] args) throws IOException {
        // 1 创建
        FileReader fileReader = new FileReader("e://hahah.txt");
        FileWriter fileWriter = new FileWriter("e://hahah2.txt");
        // 2 读写
        int data=0;
        while ((data=fileReader.read())!=-1){
            fileWriter.write(data);
            fileWriter.flush();
        }
        // 3 关闭
        fileReader.close();
        fileWriter.close();
        System.out.println("读写完成");
    }
}

image-20210206160818959

字符流不能读取图片原因分析:

二进制文件没有字符编码,不能读取,读取到的都是乱码,更别提写入了!

字符缓冲流

BufferedReader / BufferedWriter

高效读写、支持输入换行符、可一次写一行读一行

image-20210206203051802

package IO.fileStream;

import java.io.*;

public class Demo06 {
    public static void main(String[] args) throws IOException {
        // 1 创建缓冲流
        FileReader fileReader = new FileReader("e://writer.txt");
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        // 2 读取
        /*
        int data=0;
        while ((data=bufferedReader.read())!=-1){
            System.out.print((char) data);
        }
        */
        // 3 readline()
        String line=null;
        while ((line=bufferedReader.readLine())!=null){
            System.out.println(line);
        }
        // 4 关闭
        bufferedReader.close();
    }
}

image-20210206164102160

image-20210206203204255

package IO.charStream;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class Demo05 {
    public static void main(String[] args) throws IOException {
        // 1. 创建BufferedWriter对象
        FileWriter fileWriter = new FileWriter("e://writer.txt");
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        // 2. 写入
        for (int i = 0; i < 6; i++) {
            bufferedWriter.write("Java是世界上最好的语言!");
            bufferedWriter.write("\n");// 写入一个换行符
            bufferedWriter.flush();
        }
        // 3. 关闭
        bufferedWriter.close();
    }
}

image-20210206162729146

打印流(PrintWriter)

封装了print() / println() 方法 支持写入后换行

支持数据原样打印

image-20210206203330231

package IO.fileStream;

import java.io.FileNotFoundException;
import java.io.PrintWriter;

public class Demo07 {
    public static void main(String[] args) throws FileNotFoundException {
        // 1 创建打印流
        PrintWriter printWriter = new PrintWriter("e://printwriter.txt");
        // 2 打印
        printWriter.write(97);
        printWriter.println(98);
        printWriter.println('a');
        printWriter.println('最');
        printWriter.append((char) 97);
        // 3 关闭
        printWriter.close();
        System.out.println("进程完毕!");
    }
}

image-20210206165158917

转换流

桥转换流 InputStreamReader / OutputStreamWriter

可将字节流转换为字符流

可设置字符的编码方式

image-20210206203459727

package IO.fileStream;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Demo08 {
    public static void main(String[] args) throws IOException {
        // 1 创建InputStreamReader对象
        FileInputStream fileInputStream = new FileInputStream("e://a.jpg");
        InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");
        // 2 读取文件
        int data=0;
        while ((data=inputStreamReader.read())!=-1){
            System.out.println(data);
        }
        // 3 关闭
        inputStreamReader.close();
    }
}

image-20210206170457804

image-20210206203718881

package IO.fileStream;

import java.io.*;

public class demo09 {
    public static void main(String[] args) throws IOException {
        // 1 创建InputStreamReader对象
        FileInputStream fileInputStream = new FileInputStream("e://a.jpg");
        InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");
        // 2 OutputStreamWriter对象
        FileOutputStream fileOutputStream = new FileOutputStream("e://c.jpg");
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"GBK");
        // 3 读取文件
        int data=0;
        while ((data=inputStreamReader.read())!=-1){
            // 4 写入文件
            System.out.println(data);
            outputStreamWriter.write(data);
            outputStreamWriter.flush();
        }

        inputStreamReader.close();
        outputStreamWriter.close();

        System.out.println("储存完毕");

    }
}

image-20210206172130157

7.File类

概念:代表物理盘符中的一个文件或者文件夹

image-20210206203811980

文件操作

package IO.File;
import javax.xml.crypto.Data;
import java.io.File;
import java.util.Date;

//File类的使用
//1. 分隔符
//2. 文件操作
//3. 文件夹操作
public class Demo01 {
    public static void main(String[] args) throws Exception {
        separator();
        touchFile("e://a.txt");
        //removeFile("e://a.txt");
        //jvmRemove("e://a.txt");
        catFileInfo("e://a.txt");
        judgeFile("e://a.txt");
    }
    // 1 分隔符
    public static void separator(){
        System.out.println("路径分隔符:" + File.pathSeparator);
        System.out.println("名称分隔符:" + File.separator);
    }
    // 2 文件操作
    // 2.1 创建文件
    public static void touchFile(String url) throws Exception {
        File file = new File(url);
        if (!file.exists()) {
            System.out.println("创建结果:" + file.createNewFile());
        } else {
            System.out.println("文件已存在!");
        }
    }
    // 2.2 删除文件
    public static void removeFile(String url)throws Exception{
        File file = new File(url);
        if (file.exists()){
            System.out.println("删除结果:"+file.delete());
        }else{
            System.out.println("文件不存在呀,主人!");
        }
    }
    // 2.3 使用JVM退出时删除文件
    public static void jvmRemove(String url) throws InterruptedException {
        File file = new File(url);
        if (file.exists()){
            file.deleteOnExit();
            Thread.sleep(5000);
        }else{
            System.out.println("文件不存在呀,主人!");
        }
    }
    // 3 获取文件信息
    public static void catFileInfo(String url){
        File file = new File(url);
        if (file.exists()){
            System.out.println("文件的绝对路径:"+file.getAbsoluteFile());
            System.out.println("文件的路径:"+file.getPath());
            System.out.println("文件名称:"+file.getName());
            System.out.println("文件的父目录:"+file.getParent());
            System.out.println("文件的长度:"+file.length());
            System.out.println("文件的修改时间:"+(new Date(file.lastModified()).toLocaleString()));
        }else{
            System.out.println("文件不存在呀,主人!");
        }
    }
    // 4 判断
    public static void judgeFile(String url) throws InterruptedException {
        File file = new File(url);
        if (file.exists()){
            System.out.println("文件可读:"+file.canRead());
            System.out.println("文件可写:"+file.canWrite());
            System.out.println("文件可执行:"+file.canExecute());
            System.out.println("是否是文件"+file.isFile());
            System.out.println("文件是否隐藏了:"+file.isHidden());
        }else{
            System.out.println("文件不存在呀,主人!");
        }
    }
    
}

文件夹操作

package IO.File;

import java.io.File;
import java.util.Date;

public class Demo02 {
    public static void main(String[] args) throws Exception {
        //touchDir("e://aaa");
        //removeDir("e://aaa");
        //jvmRemove("e://aaa");
        catDirInfo("e://aaa");
    }
    // 1 分隔符
    public static void separator(){
        System.out.println("路径分隔符:" + File.pathSeparator);
        System.out.println("名称分隔符:" + File.separator);
    }
    // 2 文件操作
    // 2.1 创建文件
    public static void touchDir(String url) throws Exception {
        File dir = new File(url);
        if (!dir.exists()) {
            System.out.println("创建结果:" + dir.mkdir());
        } else {
            System.out.println("文件已存在!");
        }
    }
    // 2.2 删除文件夹(只能删除空目录)
    public static void removeDir(String url)throws Exception{
        File dir = new File(url);
        if (dir.exists()){
            System.out.println("删除结果:"+dir.delete());
        }else{
            System.out.println("文件不存在呀,主人!");
        }
    }
    // 2.3 使用JVM退出时删除文件
    public static void jvmRemove(String url) throws InterruptedException {
        File dir = new File(url);
        if (dir.exists()){
            dir.deleteOnExit();
            Thread.sleep(5000);
        }else{
            System.out.println("文件不存在呀,主人!");
        }
    }
    // 3 获取文件信息
    public static void catDirInfo(String url){
        File dir = new File(url);
        if (dir.exists()){
            System.out.println("文件夹的绝对路径:"+dir.getAbsolutePath());
            System.out.println("文件夹的路径:"+dir.getPath());
            System.out.println("文件夹名称:"+dir.getName());
            System.out.println("文件夹的父目录:"+dir.getParent());
            System.out.println("文件夹的修改时间:"+(new Date(dir.lastModified()).toLocaleString()));
        }else{
            System.out.println("文件不存在呀,主人!");
        }
    }
    // 4 判断
    public static void judgeDir(String url) throws InterruptedException {
        File dir = new File(url);
        if (dir.exists()){
            System.out.println("文件可读:"+dir.canRead());
            System.out.println("文件可写:"+dir.canWrite());
            System.out.println("文件可执行:"+dir.canExecute());
            System.out.println("是否是文件夹"+dir.isDirectory());
            System.out.println("文件是否隐藏了:"+dir.isHidden());
        }else{
            System.out.println("文件不存在呀,主人!");
        }
    }
}

image-20210206185534150

递归遍历文件夹

package IO.File;

import java.io.File;
import java.util.Date;

public class Demo02 {
    public static void main(String[] args) throws Exception {
        listDir("e://");
    }
    // 5 遍历文件夹
    public static void listDir(String url){
        File dir = new File(url);
        String[] list = dir.list();
        for (String s : list) {
            System.out.println(s);
        }
    }
}

image-20210206190739847

递归删除文件夹

package IO.File;

import java.io.File;
import java.net.URL;
import java.util.Date;

public class Demo02 {
    public static void main(String[] args) throws Exception {
        deleteDir("e://aaa");
        
	// 递归删除文件夹
    public static void deleteDir(String url){
        File dir = new File(url);
        File[] files = dir.listFiles();
        int count=files.length;
        if(files != null && files.length > 0){
            for(File file : files){
                System.out.println(file+"删除结果:"+file.delete());
                count--;
            }
        }

        if(count==0) {
            dir.delete();
            System.out.println("删除完成!");
        }
    }
}

image-20210206192810593

FileFilter接口

这是一个功能界面,因此可以用作lambda表达式或方法引用的赋值对象。

//FileFilter接口的使用
package IO.File;

import java.io.File;
import java.io.FileFilter;

public class Demo03 {
    public static void main(String[] args) {
        File dir = new File("C:\\Users\\Bai\\Pictures");
        File[] files = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                if (pathname.getName().endsWith("jpg")){
                    return true; //符合条件返回true
                }else{
                    return false;
                }
            }
        });
        for (File file : files) {
            System.out.println(file.getName());
        }
    }
}

image-20210206195109460

8.小结

img

二、Java集合框架

000

1.集合的概念

  • 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能。

和数组区别

  • 数组长度固定,集合长度不固定

  • 数组可以存储基本类型和引用类型,集合只能存储引用类型

差异

  • 位置: java.util.*;

java.long.object

常见集合分类

Collection 接口的接口 对象的集合(单列集合)
├——-List 接口:元素按进入先后有序保存,可重复
│—————-├ LinkedList 接口实现类, 链表, 插入删除, 没有同步, 线程不安全
│—————-├ ArrayList 接口实现类, 数组, 随机访问, 没有同步, 线程不安全
│—————-└ Vector 接口实现类 数组, 同步, 线程安全
│ ———————-└ Stack 是Vector类的实现类
└——-Set 接口: 仅接收一次,不可重复,并做内部排序
├—————-└HashSet 使用hash表(数组)存储元素
│————————└ LinkedHashSet 链表维护元素的插入次序
└ —————-TreeSet 底层实现为二叉树,元素排好序

Map 接口 键值对的集合 (双列集合)
├———Hashtable 接口实现类, 同步, 线程安全
├———HashMap 接口实现类 ,没有同步, 线程不安全-
│—————–├ LinkedHashMap 双向链表和哈希表实现
│—————–└ WeakHashMap
├ ——–TreeMap 红黑树对所有的key进行排序
└———IdentifyHashMap

2.Collection接口

Collection体系集合

Collection体系集合

Collection父接口

20180803193423722

Collection的简单使用

package aggregate.Collection;

import java.util.ArrayList;
import java.util.Iterator;

public class Demo01 {
    //Collection接口的使用
    //添加元素--删除元素--遍历元素--判断元素

    public static void main(String[] args) {
        //创建集合
        ArrayList<Object> collection = new ArrayList<>();
        //添加元素
        collection.add("冰冰");
        collection.add("Lisa");
        collection.add("IU");
        collection.add("书欣");
        collection.add("白小飞");
        //打印元素个数
        System.out.println(collection.size());
        //打印collection
        System.out.println(collection);

        //删除元素
        collection.remove("白小飞");
        //打印元素个数
        System.out.println("老婆的个数:"+collection.size());
        //打印collection
        System.out.println(collection);

        //遍历集合
        //增强for循环,不能使用普通for,因为没有下标
        /*
        for (int i = 0; i < collection.size(); i++) {
            System.out.println(collection[i]);
        }
         */
        System.out.println("===增强for循环遍历====");
        for (Object o : collection) {
            System.out.println(o);
        }
        System.out.println("===Iterator遍历====");
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            String string = (String) iterator.next();
            System.out.println(string);
            // 在迭代过程中不允许使用collection.remove()方法
            //collection.remove(string); ConcurrentModificationException:collection
            iterator.remove();
        }
        System.out.println("======判断======");
        System.out.println(collection.isEmpty());
        System.out.println(collection.contains("白小飞"));

        System.out.println("====删除集合全部元素=====");
        //删除集合全部
        collection.clear();
        //判断集合是否为空
        System.out.println(collection.isEmpty());
        //打印collection
        System.out.println(collection);

    }
}

image-20210203114152624

内存分析

image-20210203220859635

3.List集合

List子接口

特点:有序、有下标、元素可以重复。

package aggregate.List;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

//List接口的使用
public class Demo01 {
    public static void main(String[] args) {

        //先创建集合
        ArrayList arrayList = new ArrayList();
        //添加元素
        arrayList.add("小米");
        arrayList.add("小米");
        arrayList.add("苹果");
        arrayList.add("华为");

        System.out.println("========按照索引进行添加============");
        arrayList.add(0,"荣耀");
        //打印个数
        System.out.println(arrayList.size());
        System.out.println(arrayList.toString());
        //删除
        arrayList.remove("小米");
        System.out.println(arrayList.toString());
        System.out.println("===========按照下标索引进行删除==========");
        arrayList.remove(1);
        System.out.println(arrayList.toString());
        //遍历
        System.out.println("========普通for循环遍历==========");
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println(arrayList.get(i));
        }
        System.out.println("======增强for循环遍历========");
        for (Object o : arrayList) {
            System.out.println(o);
        }
        System.out.println("=======迭代器======");
        Iterator iterator = arrayList.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("=========列表迭代器从前往后=========");
        ListIterator listIterator = arrayList.listIterator();
        while (listIterator.hasNext()){
            System.out.println(listIterator.nextIndex()+":"+listIterator.next());
        }
        System.out.println("=========列表迭代器从后往前=========");
        while (listIterator.hasPrevious()){
            System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
        }
        System.out.println("==========判断=========");
        System.out.println(arrayList.contains("小米"));
        System.out.println(arrayList.contains("荣耀"));
        System.out.println("=========获取元素位置==========");
        System.out.println(arrayList.indexOf("华为"));
    }
}

image-20210203223533429

package aggregate.List;

import java.util.ArrayList;
import java.util.List;

public class Demo02 {
    public static void main(String[] args) {
        List arrayList = new ArrayList();

        //添加数字(自动集箱)
        arrayList.add(10);
        arrayList.add(30);
        arrayList.add(10);
        arrayList.add(50);

        arrayList.remove(0);
        System.out.println(arrayList.toString());
        System.out.println("========通过数值进行删除的方法=======");
        arrayList.remove((Object) 10);
        System.out.println(arrayList.toString());
        arrayList.remove(new Integer(50));
        System.out.println(arrayList.toString());

        //添加数据
        arrayList.add(10);
        arrayList.add(30);
        arrayList.add(10);
        arrayList.add(50);

        System.out.println("添加数据后:"+arrayList);
        System.out.println("=======返回子集合=====");
        List list = arrayList.subList(2,3);
        //List list02 = arrayList.subList(2,6); 越界
        System.out.println(list);
    }
}

image-20210203224825285

List的实现类

ArrayList(重点)
  • 数组结构实现,查询快、增删慢;
  • JDK1.2版本,运行效率快、线程不安全。
package aggregate.List.ArrayList;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

//ArrayList的使用
//存储结构:数组 ,查找 遍历速度快,增删慢
public class Demo01 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        //添加元素
        Student g1 = new Student("冰冰", 18);
        Student g2 = new Student("虞书欣", 18);
        Student g3 = new Student("李知恩", 18);
        Student g4 = new Student("白小飞", 18);

        arrayList.add(g1);
        arrayList.add(g2);
        arrayList.add(g3);
        arrayList.add(0,g4);

        System.out.println(arrayList.toString());

        arrayList.remove(2);

        System.out.println("=====迭代器======");
        Iterator iterator = arrayList.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next().toString());
        }
        System.out.println("=====列表迭代器======");
        ListIterator listIterator = arrayList.listIterator();
        while (listIterator.hasNext()){
            System.out.println(listIterator.next().toString());
        }
        System.out.println("反向List迭代器");
        while (listIterator.hasPrevious()){
            System.out.println(listIterator.previous().toString());
        }
        System.out.println("=======判断=======");
        System.out.println(arrayList.contains("白小飞"));
        System.out.println(arrayList.toString());
        System.out.println("========找位置=======");
        System.out.println(arrayList.indexOf("白小飞"));

    }
}

image-20210203231141392

删除元素 arrayList.remove(new Student("name", 10));

这里重写了 equals(this == obj) 方法

public boolean equals(Object obj){
  //1 判断是不是同一个对象
  if(this == obj){
    return true;
  }
  //2 判断是否为空
  if(obj == null){
    return false;
  }
  //3 判断是否是Student类型
  if(obj instanceof Student){
    Student == (Student)obj;
    //4 比较属性
    if(this.name.equals(s.getName()) && this.age == s.getAge()){
      return true;
    }
  }
  //5 不满足条件返回false
  return false;
}

原码分析

DEFAULT_CAPACITY = 10; //默认容量

image-20210204122210858

注意:如果没有向集合中添加任何元素时,容量0;添加一个后,容量为10;每次扩容是原来的1.5倍

image-20210204122841574

image-20210204123132586

image-20210204123351858

image-20210204123414185

elementData存放元素的数组

size 实际元素个数

image-20210204122719123

Vector(向量)
  • 数组结构实现,查询快、增删慢;。
  • JDK1.0版本,运行效率慢、线程安全。
package aggregate.List.Vector;

import java.util.*;

public class Demo01 {
    public static void main(String[] args) {
        System.out.println("====创建===");
        Vector vector = new Vector<>();
        System.out.println("====添加元素===");
        vector.add("王冰冰");
        vector.add("Lisa");
        vector.add("白小飞");
        vector.add("王冰冰");
        vector.add("IU");
        System.out.println("===删除元素===");
        vector.remove("白小飞");
        vector.remove(0);
        System.out.println("===打印集合===");
        System.out.println(vector.toString());
        System.out.println("===普通for遍历===");
        for (int i = 0; i < vector.size(); i++) {
            System.out.println(vector.get(i));
        }
        System.out.println("===增强for遍历===");
        for (Object o : vector) {
            String str = (String)o;
            System.out.println(str);
        }
        System.out.println("===普通迭代器===");
        Iterator iterator = vector.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("===List迭代器遍历===");
        ListIterator listIterator = vector.listIterator();
        while (listIterator.hasNext()){
            System.out.println(listIterator.next().toString());
        }
        System.out.println("===List反向迭代器遍历===");
        while (listIterator.hasPrevious()){
            System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
        }
        System.out.println("===特有枚举器===");
        Enumeration elements = vector.elements();
        while (elements.hasMoreElements()){
            System.out.println((String)elements.nextElement());
        }
        System.out.println("===判断冰冰是否存在===");
        System.out.println(vector.contains("王冰冰"));
        System.out.println("===判断是否为空===");
        System.out.println(vector.isEmpty());
        System.out.println("===获取第一个元素===");
        System.out.println(vector.firstElement());
        System.out.println("===获取最后一个元素===");
        System.out.println(vector.lastElement());
        System.out.println("===获取下标为2的元素===");
        System.out.println(vector.elementAt(2));
    }
}

image-20210204162119291

LinkedList
  • 链表结构实现,增删快,查询慢。

LinkedLis

package aggregate.List.LinkedList;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

//LinkedList
//存储结构:双向链表
public class Demo01 {
    public static void main(String[] args) {
        System.out.println("===创建集合===");
        LinkedList linkedList = new LinkedList<>();
        System.out.println("===添加元素===");
        Student stu1 = new Student("白小飞", 10);
        Student stu2 = new Student("杨洪利", 10);
        Student stu3 = new Student("哈哈哈", 10);
        linkedList.add(stu1);
        linkedList.add(stu2);
        linkedList.add(stu3);
        System.out.println("===输出长度及数据===");
        System.out.println(linkedList.size());
        System.out.println(linkedList.toString());
        System.out.println("====删除数据===");
        linkedList.remove(2);
        System.out.println(linkedList.toString());
        System.out.println("===for遍历===");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }
        System.out.println("===增强for遍历===");
        for (Object o : linkedList) {
            Student o1 = (Student) o;
            System.out.println(o1);
        }
        System.out.println("===普通迭代器===");
        Iterator iterator = linkedList.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next().toString());
        }
        System.out.println("===listIterator迭代器===");
        ListIterator listIterator = linkedList.listIterator();
        while (listIterator.hasNext()){
            System.out.println(listIterator.next());
        }
        System.out.println("===listIterator反向迭代器===");
        while (listIterator.hasPrevious()){
            System.out.println(listIterator.previous().toString());
        }
        System.out.println("===判断并获取===");
        System.out.println(linkedList.contains("白小飞"));
        System.out.println(linkedList.indexOf(stu1));
    }
}

image-20210204163335185

源码分析

int size():集合的大小

Node first:链表的头节点!

Node last:链表的尾节点

image-20210204164057185

image-20210204164142424

image-20210204164212640

remove速度快:只是改变节点关系,数据不需要移动

image-20210204164655690

LinkedLis

不同结构实现方式

image-20210204165047435

  • ArrayList:必须开辟连续空间,查询快,增删慢。

  • LinkedList:无需开辟连续空间,查询慢,增删快。

List与数组转化

//list.toArrary()

package aggregate.List;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Demo03 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        Integer[] array = list.toArray(new Integer[10]);
        Integer[] array1 = list.toArray(new Integer[2]);
        System.out.println("objects1 == objects2 : "+(array == array1));
        System.out.println("show array: "+ Arrays.toString(array));
        System.out.println("show array1: "+ Arrays.toString(array1));
        System.out.println("show list: "+list);
    }
}

image-20210205204801334

package aggregate.List;

import java.util.Arrays;
import java.util.List;

//数组转集合

public class Demo04 {
    public static void main(String[] args) {
        String[] students = {"宰相","皇帝","大臣","御史大夫"};
        List<String> strings = Arrays.asList(students);
        //这个集合是受限集合,不支持增加删除
        //System.out.println(strings);
        //strings.add("秦王");
        //strings.remove("宰相");
        System.out.println(strings);
    }
}

这个集合是受限集合,不支持增加删除操作!

image-20210205205543031

//把基本类型数组转成集合时,需要修改为包装类型
Integer[] nums01={1,2,3,5,6};
List<Integer> integers = Arrays.asList(nums01);
//List<int[]> integers02 = Arrays.asList(nums01);
System.out.println(integers);

拓展

Java中int和Integer关系是比较微妙的。关系如下:

  1. int是基本的数据类型,Integer是int的封装类(复杂数据类型);
  2. int和Integer都可以表示某一个数值;
  3. int和Integer不能够互用,因为他们两种不同的数据类型;
  4. 在类进行初始化时int类的变量初始为0.而Integer的变量则初始化为null

小结:只是用来进行一些加减乘除的运算or作为参数进行传递,那么就可以直接声明为int基本数据类型,但如果要像对象一样来进行处理,那么就要用Integer来声明一个对象,因为java是面向对象的语言,因此当声明为对象时能够提供很多对象间转换的方式。

4.泛型

泛型

本质是参数化类型,把类型作为参数传递

语法: <T,.....>成为类型占位符,表示一种引用类型,可以写多个逗号隔开

  • 泛型类
package aggregate.SegmentFault;

//泛型类
//语法:类名<T>
//T表示类型占位符,可以有多个

public class Demo01<T> {

    //泛型可以用于创建变量,但是不能实例化对象 new
    //使用泛型创建变量
    T t;
    //作为方法的参数
    public void print(T t){
        System.out.println(t);
    }
    //泛型作为方法的返回值
    public T getT(){
        return t;
    }

}
package aggregate.SegmentFault;

//泛型类的创建
public class TestDemo01 {
    public static void main(String[] args) {
        Demo01<String> demo01 = new Demo01<>();
        demo01.t="hello";
        demo01.print("大家好");
        System.out.println(demo01.getT());

        Demo01<Integer> integerDemo01 = new Demo01<>();
        integerDemo01.t=12;
        integerDemo01.print(15);
        System.out.println(integerDemo01.getT());
    }
}

注意:1.泛型只能使用引用类型;2.不同泛型类型对象不能相互赋值

  • 泛型接口
//Demo02
package aggregate.SegmentFault;

//泛型接口
//注意:不能创建泛型静态常量
public interface Demo02<K> {

    String name="白小飞";

    K server(K k);
}
//方法一
package aggregate.SegmentFault;

//继承string类型的范型类接口
public class Demo02Impl01 implements Demo02<String>{

    @Override
    public String server(String s) {
        System.out.println(s);
        return s;
    }
}
//方法二
package aggregate.SegmentFault;

//实现泛型类接口的类也是泛型类
public class Demo02Impl02<T> implements Demo02<T>{
    @Override
    public T server(T t) {
        System.out.println(t);
        return t;
    }
}
//main()
package aggregate.SegmentFault;

public class TestDemo02 {
    public static void main(String[] args) {
        Demo02Impl01 demo02 = new Demo02Impl01();
        demo02.server("白小飞");

        Demo02Impl02<String> demo02Impl02 = new Demo02Impl02<>();
        demo02Impl02.server("hello");
    }
}

image-20210204213633053

  • 泛型方法
package aggregate.SegmentFault;

//泛型方法

public class Demo03 {
    public <t> void say(){
        System.out.println("say!");
    }

    public <T> T haha(T t){
        System.out.println(t);
        return t;
    }
}
package aggregate.SegmentFault;

//调用泛型方法
//类型不需要定义,它会根据传入的值确定类型
public class TestDemo03 {
    public static void main(String[] args) {
        Demo03 demo03 = new Demo03();
        demo03.say();
        demo03.haha("中国加油!");
        demo03.haha(111);
    }
}

好处

  1. 提高代码重用性 ,类似于重载,一个方法可以传递各种参数!
  2. 防止类型转换异常,提高代码安全性

泛型集合

package aggregate.SegmentFault;

import java.util.Iterator;
import java.util.LinkedList;

public class Demo04 {
    public static void main(String[] args) {
        System.out.println("原迭代器遍历");
        LinkedList<Object> objects = new LinkedList<>();
        objects.add("划水");
        objects.add("摸鱼");
        objects.add("吃饭");
        objects.add(555);
        objects.add(666);
        Iterator<Object> iterator = objects.iterator();
        //while (iterator.hasNext()){
            //System.out.println(iterator.toString());
            //String str = (String) iterator.next();
            //System.out.println(str);
        //}

        LinkedList<Integer> integers = new LinkedList<>();
        integers.add(1);
        integers.add(4);
        integers.add(3);
        integers.add(2);
        Iterator<Integer> iterator1 = integers.iterator();
        while (iterator1.hasNext()){
            System.out.println(iterator1.next());
        }

        Student stu1 = new Student("白小飞", 12);
        Student stu2 = new Student("冰冰", 12);
        Student stu3 = new Student("虞书欣", 12);
        Student stu4 = new Student("IU", 12);
        LinkedList<Student> students = new LinkedList<>();
        students.add(stu1);
        students.add(stu2);
        students.add(stu3);
        students.add(stu4);
        Iterator<Student> iterator2 = students.iterator();
        while (iterator2.hasNext()){
            System.out.println(iterator2.next());
        }
    }
}

image-20210204224544183

5.Set集合

Set接口

package aggregate.Set.HashSet;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Demo01 {
    //测试 Set 接口的使用
    //特点:无序 、没有下标 、 不能重复

    public static void main(String[] args) {
        //创建集合
        Set<String> hashSet = new HashSet<>();
        //添加数据
        //不能重复!重复的将不会存储!
        hashSet.add("白小飞");
        hashSet.add("白小飞");
        hashSet.add("王冰冰");
        hashSet.add("吃花椒");
        hashSet.add("喵酱");
        System.out.println(hashSet.size());
        System.out.println(hashSet.toString());
        //删除操作
        //hashSet.remove("白小飞");
        //遍历
        System.out.println("===使用增强for===");
        for (String s : hashSet) {
            System.out.println(s);
        }

        System.out.println("===使用迭代器===");
        Iterator<String> iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("===判断===");
        System.out.println(hashSet.contains("王冰冰"));
    }
}

image-20210204234823341

Set实现类

  • HashSet
package aggregate.Set.HashSet;

import java.util.HashSet;
import java.util.Iterator;

//HashSet
//存储结构:哈希表(数组+链表+红黑树)
public class Demo02 {
    public static void main(String[] args) {
        //新建集合
        HashSet<String> hashSet = new HashSet<>();
        //添加元素
        hashSet.add("王冰冰");
        hashSet.add("蔡徐坤");
        hashSet.add("双厨");
        hashSet.add("央视");
        System.out.println(hashSet.size());
        System.out.println(hashSet);
        //删除元素
        hashSet.remove("央视");
        hashSet.add("央视");
        System.out.println(hashSet);
        System.out.println("===增强for迭代===");
        for (String s : hashSet) {
            System.out.println(s);
        }
        System.out.println("===迭代器===");
        Iterator<String> iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("===判断===");
        System.out.println(hashSet.contains("蔡徐坤"));
    }

}

image-20210204235919868

package aggregate.Set.HashSet;

import java.util.HashSet;
import java.util.Iterator;

public class Demo03 {
    public static void main(String[] args) {
        //创建集合
        HashSet<Person> people = new HashSet<Person>();
        Person p1 = new Person("白小飞", 11);
        Person p2 = new Person("qdwq", 11);
        Person p3 = new Person("qdqw", 11);
        Person p4 = new Person("caixe", 11);
        //添加元素
        people.add(p1);
        people.add(p2);
        people.add(p3);
        people.add(p4);
        people.add(new Person("lisa",18));
        //下面new又存储了一个相同的元素!!
        //存了两个白小飞!!
        people.add(new Person("白小飞", 11));
        //输出元素
        System.out.println(people.toString());
        System.out.println("===增强for循环===");
        for (Person person : people) {
            System.out.println(person.toString());
        }
        System.out.println("===迭代器循环===");
        Iterator<Person> iterator = people.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

image-20210205001302866

存储过程(重复依据)

  1. 根据hashCode计算保存的位置,如果位置为空,直接保存,若不为空,进行第二步
  2. 再执行equals方法,如果equals为true,则认为是重复,否则形成链表
//方法重写 可以通过new进行remove删除以及不能通过new重复存储了 
//alt+insert 重写 hasCode 和 equal方法
@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

在hashCode方法中存在了一个31,它的作用:

1.31是一个质数,尽量减少散列冲突

2.31提高执行效率 31*i=i<<5-i (将乘法换成移位操作,底层计算,效率快)

image-20210205115837148

TreeSet

  • 基于排列顺序实现元素不重复
  • 实现了SortedSet接口,对集合元素自动排序
  • 元素对象的类型必须实现Comparable接口,指定排序规则
  • 通过CompareTo方法确定是否为重复元素

TreeSet

普通数据默认比较
package aggregate.TreeSet;

import java.util.Iterator;
import java.util.TreeSet;
//使用TreeSet保存数据
//存储结构:红黑树

public class Demo01 {
    public static void main(String[] args) {
        TreeSet<String> treeSet = new TreeSet<String>();
        treeSet.add("asda");
        treeSet.add("xya");
        treeSet.add("ii");
        treeSet.add("a");
        System.out.println("个数:"+treeSet.size());
        System.out.println(treeSet.toString());
        System.out.println("===增强for===");
        for (String s : treeSet) {
            System.out.println(s);
        }
        System.out.println("===迭代器===");
        Iterator<String> iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

image-20210205125205703

实现 Comparable接口
//Person
package aggregate.TreeSet;

import java.util.Objects;

public class Person implements Comparable<Person> {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = 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;
    }

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

    //比较规则:先按姓名比,再按年龄比
    @Override
    public int compareTo(Person o) {
        int name=this.name.compareTo(o.name);
        int age=this.age-o.age;
        return name==0?age:name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
package aggregate.TreeSet;

import java.util.Iterator;
import java.util.TreeSet;
//使用TreeSet保存数据
//存储结构:红黑树
//要求:元素必须要实现 Comparable接口,CompareTo() 返回值为0,认为是重复元素

public class Demo02 {
    public static void main(String[] args) {
        TreeSet<Person> people = new TreeSet<>();
        Person p1 = new Person("xyz", 11);
        Person p2 = new Person("lisa",11);
        Person p3 = new Person("bai",11);
        Person p4 = new Person("iu",11);
        people.add(p1);
        people.add(p2);
        people.add(p3);
        people.add(p4);
        System.out.println(people.size());
        System.out.println(people.toString());
        Person p5 = new Person("iu",18);
        Person p6 = new Person("iu",18);
        people.add(p5);
        people.add(p6);
        System.out.println(people.toString());
        for (Person person : people) {
            System.out.println(person.toString());
        }
        Iterator<Person> iterator = people.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //重写hashSet方法后,将不会储存重复的new 对象
        //重写hashSet方法后,可以通过new 对象删除具有相同属性的元素
        System.out.println(people.toString());
        people.add(new Person("iu",11));
        System.out.println(people.toString());
        people.remove(new Person("iu",18));
        System.out.println(people.toString());
    }
}

image-20210205130919657

Comparator 实现定制比较(定制器)
package aggregate.TreeSet;

//Comparator 定制比较
import java.util.Comparator;
import java.util.TreeSet;

public class Demo03 {
    public static void main(String[] args) {
        
        //创建集合并定制比较规则
        TreeSet<Person> people = new TreeSet<>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                int n1 = o1.getName().compareTo(o2.getName());
                int n2 = o1.getAge()-o2.getAge();
                return n1==0?n2:n1;
            }
        });

        Person p1 = new Person("xyz", 11);
        Person p2 = new Person("lisa",11);
        Person p3 = new Person("bai",11);
        Person p4 = new Person("iu",11);

        people.add(p1);
        people.add(p2);
        people.add(p3);
        people.add(p4);

        System.out.println(people);
    }
}

image-20210205132114298

example

要求:使用TreeSet集合实现字符串长度排序

compare :

1:前面的数>后面的数,是降序(从大到小)排列,如果想要改为升序排列,就需要返回1

-1:前面的数<后面的数,是升序(从小到大)排列,不改变位置就返回-1;

0:二者相等,不进行交换,也就不排序。

package aggregate.TreeSet;

import java.util.Comparator;
import java.util.TreeSet;

public class Demo04 {
    public static void main(String[] args) {
        TreeSet<String> strings = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int n1=o1.length()-o2.length();
                //n1 == 0 说明 长度相等
                //compare :
                //1:前面的数>后面的数,是降序(从大到小)排列,如果想要改为升序排列,就需要返回1
                //-1:前面的数<后面的数,是升序(从小到大)排列,不改变位置就返回-1;
                //0:二者相等,不进行交换,也就不排序。
                int n2=o1.compareTo(o2);
                //按照默认首字母比较
                return n1==0?n2:n1;
            }
        });
        strings.add("aaaa");
        strings.add("zasas");
        strings.add("asasd");
        strings.add("ada");
        strings.add("wd");
        System.out.println(strings);
    }
}

image-20210205133802895

6.Map集合

map集合

image-20210205135518032

Map父接口

Map接口的特点

  1. 用于存储任意键值对(key - value)
  2. 键:无序、无下标、不允许重复(唯一)
  3. 值:无序、无下标、允许重复
package aggregate.Map;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

//Map接口的使用
//特点:(1)存储键值对;(2)键不能重复,值可以重复;(3)无序
public class Demo01 {
    public static void main(String[] args) {
        HashMap<String, Integer> stringIntegerHashMap = new HashMap<>();
        stringIntegerHashMap.put("白小飞",18);
        stringIntegerHashMap.put("葫芦娃",18);
        stringIntegerHashMap.put("哈哈哈",18);
        stringIntegerHashMap.put("嘎嘎嘎",18);
        System.out.println(stringIntegerHashMap.toString());
        System.out.println("===不会增加重复元素,但是会更新value值===");
        stringIntegerHashMap.put("白小飞",21);
        System.out.println(stringIntegerHashMap.toString());
        System.out.println("===keySet遍历===");
        Set<String> strings = stringIntegerHashMap.keySet();
        for (String string : strings) {
            System.out.println(string+":"+stringIntegerHashMap.get(string));
        }
        System.out.println("===entrySet遍历===");
        Set<Map.Entry<String, Integer>> entries = stringIntegerHashMap.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
        System.out.println("===判断key与value是否存在===");
        System.out.println(stringIntegerHashMap.containsKey("白小飞"));
        System.out.println(stringIntegerHashMap.containsValue(18));
    }
}

image-20210205143743861

KeySet与EntrySet

entrySet效率较高,可一次性查出key与value。

image-20210205143246792

Map集合的实现类

HashMap(重点)

HashMap

  • 存储结构:哈希表(数组+链表+红黑树)
  • 使用key可使hashcode和equals作为重复
  • 增、删、遍历、判断与上述一致
//Student
package aggregate.Map.HashMap;

import java.util.Objects;

public class Student {
    private String name;
    private int stuNo;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getStuNo() {
        return stuNo;
    }

    public void setStuNo(int stuNo) {
        this.stuNo = stuNo;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return stuNo == student.stuNo && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, stuNo);
    }
}
//Application

package aggregate.Map.HashMap;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

//HashMap集合
//存储结构:哈希表(数组+链表+红黑树)
//使用hashCode 和 equals 方法
public class Demo01 {
    public static void main(String[] args) {
        HashMap<Student, String> studentStringHashMap = new HashMap<>();
        //key值不可以重复,但是value值可以!value值也会覆写!!
        Student stu01 = new Student("孙悟空", 100);
        Student stu02 = new Student("猪八戒", 102);
        Student stu03 = new Student("唐三藏", 103);
        studentStringHashMap.put(stu01,"上海");
        studentStringHashMap.put(stu02,"杭州");
        studentStringHashMap.put(stu03,"北京");
        System.out.println("元素个数:"+studentStringHashMap.size());
        System.out.println(studentStringHashMap.toString());
        studentStringHashMap.put(new Student("沙和尚",122),"北京");
        System.out.println("元素个数:"+studentStringHashMap.size());
        System.out.println(studentStringHashMap.toString());
        System.out.println("===添加重复元素==="); //重写hashCode 和 equals 方法实现不允许存储重复数据
        studentStringHashMap.put(new Student("唐三藏", 103),"北京");
        System.out.println("元素个数:"+studentStringHashMap.size());
        System.out.println(studentStringHashMap.toString());
        studentStringHashMap.remove(stu01);
        System.out.println(studentStringHashMap);
        //studentStringHashMap.clear();
        System.out.println("===keySet遍历===");
        Set<Student> students = studentStringHashMap.keySet();
        for (Student student : students) {
            System.out.println(student+":"+studentStringHashMap.get(student));
        }
        System.out.println("===entrySet遍历===");
        Set<Map.Entry<Student, String>> entries = studentStringHashMap.entrySet();
        for (Map.Entry<Student, String> entry : entries) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
        System.out.println("===判断是否存在===");
        System.out.println(studentStringHashMap.containsValue("泰安"));
        //由于重写了equals 和 hashSet 方法, 所以可以通过 new 一个具有相同属性的对象 删除原有元素
        System.out.println(studentStringHashMap.containsKey(new Student("唐三藏", 103)));
    }
}

image-20210205152510536

原码分析

image-20210205182956377

//默认的初始化容量为16
static final int DEFAULT_INITAL_CAPACITY = 1 << 4;

//最大的容量,容量的值必须是2的幂并且小于最大容量,最大值为2的30此房
static final int MAXMUM_CAPACITY = 1 << 30;

//加载因子默认值为0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;

//计数阀值,超过这个值将会使用树形结构替代链表结构
static final int TREEIFYTHRESHOLD = 8;

//由树形结构转换成链表结构的阀值
static final int UNTREEIFY_THRESHOLD = 6;

//树形结构最小容量为64
static final int MIN_TREEIFY_CAPACITY = 64;

//链表数组
transient Node<K, V>[] table;

//HashMap中value的集合
transient Set<Map.Entry<K, V>> entrySet;

//hashMap的长度
transient int size;
  • 刚创建hashSet时table=null size=0以节省空间

image-20210205182303236

Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
源码分析总结
  1. HashMap刚创建时,table是null,节省空间,当添加第一个元素时,table容量调整为16
  2. 当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的两倍,目的是减少调整元素的个数
  3. jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整成红黑树,目的是提高效率
  4. jdk1.8 当链表长度 <6 时 调整成链表
  5. jdk1.8 以前,链表时头插入,之后为尾插入

HashMap

HashMap与HashSet

image-20210205185143373

image-20210205185231505

image-20210205185254562

HashSet实现了 Set接口,不允许出现重复元素,但是向HashSet中存储对象必须重写对象的HashCode和equals方法。HashSet是由HashMap实现的。HashSet允许存储NULL元素,并且NULL永远存储在第一个。

HashSet

HashMap实现了Map接口,允许NULL键NULL值。使用hash寻址会发生hash冲突问题,底层使用数组加链表的结构,解决了冲突也均衡了查找和增删的效率;一般将数组中的每一个元素称作桶(segment)。

HashMap

HashTable

线程安全,运行效率慢;不允许null作为key或是value

Properties(属性集合)

hashtable的子类,要求key和value都是string,通常用于配置文件的读取

特点:

  • 1.存储属性名和属性值
  • 2.属性名和属性值都是字符串类型
  • 3.没有泛型
  • 和流有关

image-20210206214707613

package aggregate.Map;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class PropertiesDemo {
    public static void main(String[] args) throws IOException {
        // 1 创建集合
        Properties properties = new Properties();
        // 2 添加数据
        properties.setProperty("username","zhangsan");
        properties.setProperty("age","18");
        System.out.println(properties.toString());
        // 3 遍历
        // 3.1 keySet
        Set<Object> objects = properties.keySet();
        for (Object o : objects) {
            System.out.println(o+":"+properties.getProperty((String) o));
        }
        // 3.2 entrySet
        Set<Map.Entry<Object, Object>> entries = properties.entrySet();
        System.out.println(entries.toString());
        // 3.3 stringPropertyNames
        Set<String> strings = properties.stringPropertyNames();
        for (String string : strings) {
            System.out.println(string+":"+properties.getProperty(string));
        }

        // 4 和流有关的方法
        // 4.1 properties.list(printWriter)
        //PrintWriter printWriter = new PrintWriter("e://abc.txt");
        //properties.list(printWriter);
        //printWriter.close();

        // 4.2 properties.store(printWriter,"注释");
        //PrintWriter printWriter = new PrintWriter("e://xyz.txt");
        //properties.store(printWriter,"注释");
        //printWriter.close();

        System.out.println("==========");
        // 4.3 properties.load(fileInputStream);
        Properties properties1 = new Properties();
        FileInputStream fileInputStream = new FileInputStream("e://abc.txt");
        properties1.load(fileInputStream);
        fileInputStream.close();
        System.out.println(properties1.toString());
    }
}

image-20210206214418402

TreeMap
package aggregate.Map.TreeMap;

import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

//TreeMap
public class Demo01 {
    public static void main(String[] args) {
        //定制器比较
        TreeMap<Student, Integer> studentIntegerTreeMap = new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int n1=o1.getStuNo()-o2.getStuNo();
                return n1;
            }
        });
        Student s1 = new Student("白小飞", 120);
        Student s2 = new Student("呜呜呜", 121);
        Student s3 = new Student("杨洪利", 123);
        studentIntegerTreeMap.put(s1,11);
        studentIntegerTreeMap.put(s2,12);
        studentIntegerTreeMap.put(s3,15);
        System.out.println(studentIntegerTreeMap.toString());
        studentIntegerTreeMap.put(new Student("杨洪利", 123),88);
        System.out.println(studentIntegerTreeMap.toString());
        System.out.println("===删除===");
        studentIntegerTreeMap.remove(s3);
        System.out.println(studentIntegerTreeMap.toString());
        System.out.println("===keyset遍历===");
        Set<Student> students = studentIntegerTreeMap.keySet();
        for (Student student : students) {
            System.out.println(student.toString()+":"+studentIntegerTreeMap.get(student));
        }
        System.out.println("===entryset遍历===");
        Set<Map.Entry<Student, Integer>> entries = studentIntegerTreeMap.entrySet();
        for (Map.Entry<Student, Integer> entry : entries) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
        System.out.println("===判断===");
        System.out.println(studentIntegerTreeMap.containsKey(new Student("白小飞", 120)));
        System.out.println(studentIntegerTreeMap.containsValue(12));
    }
}

image-20210205193328064

7.Collections工具类

此类仅由静态方法组合或返回集合。 它包含对集合进行操作的多态算法,“包装器”,返回由指定集合支持的新集合,以及其他一些可能的和最终的。

image-20210205211930624

package aggregate.Collection;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

//Collections工具类
public class Demo03 {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(8);
        //打印
        System.out.println(list.toString());
        //排序
        Collections.sort(list);
        //打印
        System.out.println("排序后:"+list.toString());
        //binarySearch
        System.out.println(Collections.binarySearch(list, 8));
        System.out.println(Collections.binarySearch(list, 0));
        //copy复制
        ArrayList arrayList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            arrayList.add(i);
        }
        System.out.println("由于collections.copy()需要相同长度,添加数据后");
        System.out.println("arraryList:"+arrayList.toString());
        Collections.copy(arrayList,list);
        System.out.println("copy后的数据:"+arrayList);
        System.out.println("reserve倒序");
        Collections.reverse(list);
        System.out.println("reserve:"+list);
        System.out.println("乱序排列");
        Collections.shuffle(list);
        System.out.println("乱序后:"+list);

    }
}

image-20210205212108002

三、Java常见类

参考

posted @ 2022-10-10 21:38  baixf白小飞  阅读(21)  评论(0编辑  收藏  举报