Java Day16

Java

day16_2023.8.28

Set集合

Set集合中的常用方法基本上和Collection中差不多

Set集合的特点

元素不可以重复,无序(有些子类是有序的),只能存放一个null(也有不能存放null的子类)

Set集合常用子类

HashSet : 底层结构是哈希表(数组+链表)

TreeSet:底层是红黑树,有序(自然排序)

LinkedHashSet:底层是哈希表 + 链表

HashSet解析

在这里插入图片描述

注释说明

1,HashSet实现了Set接口,不保证元素的顺序,允许1一个null元素,非同步的,初始容量影响性能

2,底层实际上是一个HashMap对象

构造方法

HashSet()

构造一个新的空集合; 背景HashMap实例具有默认初始容量(16)和负载因子(0.75)。

HashSet(Collection<? extends E> c)

构造一个包含指定集合中的元素的新集合。

HashSet(int initialCapacity)

构造一个新的空集合; 背景HashMap实例具有指定的初始容量和默认负载因子(0.75)。

HashSet(int initialCapacity, float loadFactor)

构造一个新的空集合; 背景HashMap实例具有指定的初始容量和指定的负载因子。

从源码能看到,HashSet在创建的时候,都是通过HashMap来实现的

HashSet中是如何处理创建的HashMap对象的键值的?
在这里插入图片描述
pp
在这里插入图片描述
通过查看HashSet中的add方法发现,其实add()方法,就是HashMap的put方法

set中通过add方法加入的元素,都成为了对应的map对象的键

map对象中的值都是一个常量PRESENT,这个常量其实是一个空对象(new Object)

所以,其实HashSet中的数据,就是一个HashMap的键,添加、删除、获取等方法,都是通过HashMap来实现的

public class SetDemo01 {
    public static void main(String[] args) {
        //创建一个hashSet
        HashSet<String> set = new HashSet<>();
        //存放元素,无序存放,不能重复
        set.add("hello");
        set.add("hello");
        set.add("JAVA");
        set.add("WORLD");
        set.add(null);
        set.add(null);
        System.out.println(set);
        //遍历
        for (String s : set) {
            System.out.println(s);
        }
        System.out.println("----------------");
        //iterator遍历
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
HashSet的存放原理

先获取元素的hashCode()值,然后根据hashCode值,判断元素在集合中的位置,每次存入元素都会比较hashCode值,

如果hashCode值相同,再去比较元素的值或者调用equals()方法判断是否相同,如果都相同,则将相同的元素替换,如果不同,以链表形式继续往后存放。

如果hashCode值不同,那么就存放在数组的不同位置。

将来,如果存放对象到set中,需要判断对象是否相同,那么要重写对象的equals()和hashCode方法

public class SetDemo01 {
    public static void main(String[] args) {
        //创建一个hashSet
       /* HashSet<String> set = new HashSet<>();
        //存放元素,无序存放,不能重复
        set.add("hello");
        set.add("hello");
        set.add("JAVA");
        set.add("WORLD");
        set.add(null);
        set.add(null);
        System.out.println(set);
        //遍历
        for (String s : set) {
            System.out.println(s);
        }
        System.out.println("----------------");
        //iterator遍历
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        */


        HashSet<User> userSet = new HashSet<>();

        userSet.add(new User(1001,"jack",20));
        userSet.add(new User(1002,"tom",20));
        userSet.add(new User(1003,"lucy",22));
        userSet.add(new User(1001,"jack",20));
        userSet.add(new User(1004,"tony",22));

        System.out.println(userSet);
    }
}




public class User {
    private int id;
    private String name;
    private int age;

    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public User() {
    }

    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;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;

        User user = (User) o;

        if (id != user.id) return false;
        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + age;
        return result;
    }
}


TreeSet

在这里插入图片描述

注释说明

实现了NavigableSet接口,有序的(自然排序),线程不安全,底层实际是一个TreeMap

构造方法

TreeSet()

构造一个新的,空的树组,根据其元素的自然排序进行排序。

TreeSet(Collection<? extends E> c)

构造一个包含指定集合中的元素的新树集,根据其元素的 自然排序进行排序 。

TreeSet(Comparator<? super E> comparator)

构造一个新的,空的树集,根据指定的比较器进行排序。

TreeSet(SortedSet s)

构造一个包含相同元素的新树,并使用与指定排序集相同的顺序。
在这里插入图片描述
当我们在构造无参的TreeSet的时候,其实是在构造一个TreeMap对象

所以,treeSet中的元素的存放,就是按照TreeMap的键来实现存放的,treeMap的值也是做了默认的空对象常量的实现

将来如果需要存入对象到TreeSet的话,

1,这个对象要实现Comparable接口,从写compareTo()方法,实现对象的比较功能

2,在构造TreeSet对象的时候,传入Comparator对象

public class TreeSetDemo {
    public static void main(String[] args) {
       /* TreeSet<Integer> treeSet = new TreeSet<>();

        treeSet.add(4);
        treeSet.add(1);
        treeSet.add(3);
        treeSet.add(5);
        treeSet.add(3);

       // treeSet.add(null); //不能存放null

        System.out.println(treeSet);
        System.out.println( treeSet.first());
        System.out.println( treeSet.last());


        //遍历
        for (Integer integer : treeSet) {
            System.out.println(integer);
        }
        Iterator<Integer> iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        */

        TreeSet<User> userSet = new TreeSet<>();

        userSet.add(new User(1002,"jack",21));
        userSet.add(new User(1001,"TOM",20));
        userSet.add(new User(1004,"TONY",22));
        userSet.add(new User(1003,"LUCY",19));

        System.out.println(userSet);
    }
}


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

    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public User() {
    }

    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;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;

        User user = (User) o;

        if (id != user.id) return false;
        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + age;
        return result;
    }

    @Override
    public int compareTo(User o) {
        if (o.id > this.id){
            return 1;
        }
        if (o.id < this.id){
            return -1;
        }
        if (o.age > this.age){
            return -1;
        }
        if (o.age < this.age){
            return 1;
        }
        if (o.name.compareTo(this.name) > 0){
            return -1;
        }
        if (o.name.compareTo(this.name) > 0){
            return 1;
        }
        return 0;
    }
}

练习 :创建TreeSet的时候,传入Comparator

  TreeSet<User> userSet = new TreeSet<>(new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                if (o1.getId() > o2.getId()) {
                    return 1;
                }
                if (o1.getId() < o2.getId()) {
                    return -1;
                }
                if (o1.getAge() > o2.getAge()) {
                    return -1;
                }
                if (o1.getAge() < o2.getAge()) {
                    return 1;
                }
                if (o1.getName().compareTo(o2.getName()) > 0) {
                    return -1;
                }
                if (o1.getName().compareTo(o2.getName()) > 0) {
                    return 1;
                }
                return 0;
            }
        });
        userSet.add(new User(1002,"jack",21));
        userSet.add(new User(1001,"TOM",20));
        userSet.add(new User(1004,"TONY",22));
        userSet.add(new User(1003,"LUCY",19));
        System.out.println(userSet);
LinkedHashSet

在这里插入图片描述

注释说明

底层是哈希表+双向链表,就是hashMap+双向链表(底层可以看做是LinkedHashMap)

有序的,存取有序,允许存null,不能重复,线程不安全的

通过查看原码,发现LinkedHashSet中,只有几个构造方法,没有其他的普通方法,方法调用来自父类

构造方法中,都是通过super在访问父类,所以,创建LinkedHashSet,其实就是在通过HashSet创建HashMap对象
在这里插入图片描述

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();

        linkedHashSet.add("hello");
        linkedHashSet.add("world");
        linkedHashSet.add("java");
        linkedHashSet.add("hello");
        linkedHashSet.add("oracle");
        linkedHashSet.add("abc");

        System.out.println(linkedHashSet);

        //遍历
        for (String s : linkedHashSet) {
            System.out.println(s);
        }

        Iterator<String> iterator = linkedHashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
Set集合总结

HashSet : 无序、允许null,不能重复,底层是HashMap(数组+链表+红黑树),线程不安全

TreeSet :有序(自然排序),不允许null,不能重复,底层是TreeMap(红黑树),线程不安全

LinkedHashSet: 有序(存取有序),允许null,不能重复,底层是HashMap+双向链表,线程不安全

IO流

在程序中,对象、集合这些数据存储是暂时的,

一旦程序结束,数据就会丢失

为了能永久的保存程序创建的数据,需要将这些数据存放到磁盘中,以后就可以持久性的使用数据了

在Java中,通过I/O流技术可以将数据保存到本地磁盘的文件中或者二进制文件中,可以达到永久存储数据的要求

在Java中,所有的数据都可以使用流来完成读写

流就是一组有序的数据序列,将数据从一个地方带到另一个地方

根据流向的不同,可以分输入流(Input Stream) 和输出流(Output Stream)

输入流: 就将数据从输入设备(键盘、文件)中内容读取到内存中

输出流 :将数据写入到输出设备(显示器、文件、磁盘)

I/O流的分类

按照流向 主要分为 : 输入流和输出流

按照流数据单位的不同分为 : 字节流和字符流

按照功能可以分为:节点流和处理流

Java中的系统流

Java的System类,封装了程序运行时的3个系统流,分别是 :in 、 out 、err

System.in : 标准输入流,默认设备是 键盘 ,是InputStream类的一个对象

System.out: 标准输出流,默认设备是控制台

System.err : 标准错误流,默认设备是控制台

System.out和System.err 是 PrintStream的对象

public class DemoIO {
    public static void main(String[] args) {

        byte[] bytes = new byte[1024];

        System.out.println("请输入内容:");
        try {
            System.in.read(bytes); //通过read()方法也能实现文件的读取
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("输入的内容是:");
        for (int i = 0; i < bytes.length; i++) {
            System.out.print((char) bytes[i]);
        }
    }
}

File类

文件其实就是用来存放数据的,将来文件既可以作为输入设备,也可以作为输出设备,

文件和目录路径名的抽象表示。

构造方法

File(File parent, String child)

从父抽象路径名和子路径名字符串创建新的 File实例。

File(String pathname)

通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。

File(String parent, String child)

从父路径名字符串和子路径名字符串创建新的 File实例。

File(URI uri)

通过将给定的 file: URI转换为抽象路径名来创建新的 File实例。

普通方法

boolean delete()

删除由此抽象路径名表示的文件或目录。

boolean exists()

测试此抽象路径名表示的文件或目录是否存在。

String getAbsolutePath()

返回此抽象路径名的绝对路径名字符串。

String getName()

返回由此抽象路径名表示的文件或目录的名称。

String getPath()

将此抽象路径名转换为路径名字符串。

boolean isDirectory()

测试此抽象路径名表示的文件是否为目录。

boolean isFile()

测试此抽象路径名表示的文件是否为普通文件。

long length()

返回由此抽象路径名表示的文件的长度。

boolean mkdir()

创建由此抽象路径名命名的目录。

boolean createNewFile()

当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。

Java中,路径地址的写法 C:\xxx\xxx ,写在字符串中的\有转义符的意思,写地址需要写两个\

或者写成 C:/XX/XX

public class FileDemo {
    public static void main(String[] args) throws IOException {

        //指定文件的路径,创建文件对象
        File file = new File("D:\\hello.txt");
        //判断是否存在
        System.out.println(file.exists());
        //创建文件
        file.createNewFile();
        //判断是否存在
        System.out.println(file.exists());
        //length()
        System.out.println(file.length());
        //getName()
        System.out.println(file.getName());
        //getPath()
        System.out.println(file.getPath());
        //delete()
        System.out.println(file.delete()); //true
        //判断是否存在
        System.out.println(file.exists());//false
        //判断是否是目录
        System.out.println(file.isDirectory()); //false
    }
}

IO流常用类

按照流向划分的类 :

输入流 : InputStream\Reader

输出流: OutputStream\Writer

按照处理单位划分的类 :

字节流:InputStream\OutputStream

字符流 :Reader\Writer

InputStream类

InputStream是一个抽象类,这个抽象类是表示输入字节流的所有类的超类。

常用子类

ByteArrayInputStream 将字节数组转为字节输入流,从中读取数据

FileInputStream 从文件中读取数据

ObjectInputStream 将对象反序列化

PipedInputStream 连接管道输出流PipedOutputStream

SequenceInputStream 将多个字节输入流串联成一个字节输入流

FileInputStream的使用

从文件系统中的文件获取输入字节

构造方法

FileInputStream(File file)

通过打开与实际文件的连接创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。

FileInputStream(String name)

通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名name命名。

public class FileInputStreamDemo {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            //创建文件的输入流对象
            //new FileInputStream(new File("D:\\hello.txt"));
            fis = new FileInputStream("D:\\hello.txt");
            System.out.println(fis.available());  //返回可读取文件字节数
            //读取内容read()方法读完内容后,返回-1
            //System.out.println(fis.read());
            //System.out.println(fis.read());
            int data;
            //在循环体中调用read()方法,必须要给方法结果赋值,
            // 不然每次调用read()方法,都是在读取一次内容,
            // 读了之后,需要将结果返回出去
            while ((data = fis.read()) != -1){
                System.out.print((char) data);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (fis != null){  //防止空指针异常
                    fis.close(); //关闭资源
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
OutputStream类

这个抽象类是表示字节输出流的所有类的超类

ByteArrayOutputStream 向字节数组中写数据

FileOutputStream 向文件中写数据

ObjectOutputStream 将对象序列化

PipedOutputStream 连接PipedIutputStream

FileOutputStream 的使用
构造方法

FileOutputStream(File file)

创建文件输出流以写入由指定的 File对象表示的文件。

FileOutputStream(String name)

创建文件输出流以指定的名称写入文件。

public class FileOutPutDemo {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            //创建fileOutput对象
            fos = new FileOutputStream("D:\\hello.txt");
            //写内容
            String s = "abcdefg,南京邮电大学";
            //将字符串转为字节数组
            byte[] bytes = s.getBytes();
            //调用write方法,写内容
            fos.write(bytes,0,bytes.length);
            System.out.println("文件已更新!");
        }  catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (fos != null){
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
Reader类

用于读取字符流的抽象类

常用子类

BufferedReader 为其他的字符输入流提供读缓冲区

CharArrayReader 将字符数组转为字符输入流,从中读取字符

InputStreamReader 将字节输入流转为字符输入流,可以指定字符编码

StringReader 将字符串转为字符输入流,从中读取字符

FileReader InputStreamReader的子类,一般用来读取文件相关字符流

FileReader类
构造方法

FileReader(File file)

创建一个新的 FileReader ,给出 File读取。

FileReader(String fileName)

创建一个新的 FileReader ,给定要读取的文件的名称。

public class FileReaderDemo {
    public static void main(String[] args) {
        FileReader fileReader = null;
        try {
            //先创建FileReader对象
            fileReader = new FileReader("D:\\hello.txt");

            //创建一个字符数组
            char[] chars = new char[1024];
            StringBuffer sbf = new StringBuffer();
            //读取内容到字符数组
            int length;
            while ( (length = fileReader.read(chars)) != -1){
               sbf.append(chars);
            }
            System.out.println(sbf.toString());
            //System.out.println(fileReader.read());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (fileReader!= null){
                    fileReader.close();}
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

使用fileReader配合BufferedReader完成内容读取

public class FileReaderDemo02 {
    public static void main(String[] args) {
        //使用fileReader配合BufferedReader完成内容读取
        FileReader fileReader = null;
        BufferedReader bufferedReader = null;
        try {
            //先创建FileReader对象
            fileReader = new FileReader("D:\\hello.txt");
            //创建BufferedReader对象
            bufferedReader = new BufferedReader(fileReader);

            //通过BufferedReader读取内容
            String s;
            while ((s = bufferedReader.readLine()) != null){
                System.out.println(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (bufferedReader != null){
                    bufferedReader.close();
                }
                if (fileReader != null){
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
        }
    }
}
Writer类

用于写入字符流的抽象类

常用子类

BufferedWriter 为其他输出流提供写缓冲区

CharArrayWriter 向内存缓冲区的字符数组写数据

OutputStreamWriter 将字节输入流,转为字符输出流,可以指定编码格式

FileWriter OutputStreamWriter的子类,用来向文件中写数据

FileWriter的使用
构造方法

FileWriter(File file)

给一个File对象构造一个FileWriter对象。

FileWriter(String fileName)

构造一个给定文件名的FileWriter对象。

public class FileWriteDemo {
    public static void main(String[] args) {
        try {
            //创建fileWriter对象
            FileWriter fileWriter = new FileWriter("D:\\hello.txt");
            //创建BufferedWriter对象
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
            //写内容
            //fileWriter.write("你好");
            //fileWriter.write("我是南京邮电大学的学生");
            //fileWriter.write("我今年20岁");
            //fileWriter.flush();
            bufferedWriter.write("你好");
            bufferedWriter.write("我是南京邮电大学的学生");
            bufferedWriter.newLine();
            bufferedWriter.write("我今年20岁");
            bufferedWriter.flush(); //刷新缓冲区

            //再读取内容
            FileReader fileReader = new FileReader("D:\\hello.txt");
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            String s ;
            while ((s = bufferedReader.readLine())!= null){
                System.out.println(s);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放资源
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值