集合深入------理解底层。

集合的使用

前提:栈、堆、二叉树、hashcode、toString()、quesalus()的知识深入和底层理解。

1、什么是集合

复制代码
集合就是咋们所说的容器
​
前面我们学习过数组  数组也是容器
​
容器:装东西的  生活中有多少的容器呀?  水杯  教室  酒瓶  水库  只要是能装东西的 都可以看成是容器
​
我们这个集合的容器 是用来装啥的呢?  装数据?
​
数据? 一切可以被计算机识别的 文字  图片  视频  音频都是数据
​
说白了 我们今天所学习的这个集合 就跟前面的数组类似  只是底层的实现不一样而已

2、集合的分类

复制代码
主要根据我们的值的个数 可以分成 单例集合 和  双列集合
​
单例集合:简单的说 在这个容器中存放的的值 就是一个一个的  value
   单列集合的爹:Collection
​
双列集合:他在容器中存储的数据就是  键值对  key---value
   双列集合的爹:Map

3、单列集合

3.1、List集合
3.1.1、ArrayList
复制代码
ArrayList<E>   这个集合中的泛型:表示的意思其实就是对这个容器中能存放数据类型的一种约束  比如我们的泛型的数据类型是:User  那么这个容器中只能存放User类型的数据
​
这个ArrayList底层就是数组 他是有序的  地址空间是连续的  地址空间连续 就意味着能通过开始地址+偏移量来为访问 而且能重复添加数据
​
有序:一定能通过下标访问数据
​
List中所有的内容都是可以重复的....
3.1.1.1、集合的使用
复制代码
public class ArrayListTest {
​
    public static void main(String[] args) {
        //第一种方式
        List<String> list = new ArrayList<>();
        //接下来就可以向这个集合中存放数据了...
        list.add("123");
        list.add("456");
        list.add("789");
        list.add("789");
​
        List<String> list2 = new ArrayList<>();
        //接下来就可以向这个集合中存放数据了...
        list.add("12322");
        list.add("45622");
​
​
        //将list2集合中的数据 添加到 list中来
        list.addAll(list2);
​
​
        //能不能删除数据呢?
        //这个就是直接删除某一个元素
        list.remove("789");
​
        //还可以通过下标删除
        list.remove(0);
​
​
        //接下来玩下修改呢?
        list.set(0,"小波波");
​
        //获取某一个位置的元素
        String s = list.get(0);
​
        //判断这个集合中是否存在某一个元素
        boolean contains = list.contains("789");
​
        //判断集合是否为空
        boolean empty = list.isEmpty();
​
        //返货某一个元素的下标位置
        int i = list.indexOf("789");
​
        //截取集合中指定位置的元素 生成一个新的集合
        List<String> stringList = list.subList(0, 5);
​
        System.out.println("list集合的size:"+list.size());
​
        List<User> userList=new ArrayList<>();
        userList.add(new User(1,"小小","123"));
        userList.add(0,new User(0,"这里是测试","xxx"));
​
        System.out.println("userList集合的size:"+userList.size());
        System.out.println("userList中的数据是:"+userList.get(0));
    }
}
复制代码
public class ArrayListTest1 {
​
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //接下来就可以向这个集合中存放数据了...
        list.add("123");
        list.add("456");
        list.add("789");
        list.add("789");
​
        //第一种遍历方式:因为这个ArrayList本身底层是数组(Object类型的数组) 数组地址空间连续 所以我们能通过下标来访问
        for (int i = 0; i <list.size() ; i++) {
            System.out.println("集合中的值:"+list.get(i));
        }
        System.out.println("------------------------------");
​
​
        //第二种遍历方式 通过增强的for循环来玩
        for (String val:list){
            System.out.println("集合中的值:"+val);
        }
​
​
        System.out.println("------------------------------");
​
​
        //第三种遍历方式通过JDK8中的stream流来遍历
        list.stream().forEach(val->{
            System.out.println("集合中的值:"+val);
        });
​
        System.out.println("------------------------------");
​
        //第四种遍历方式:迭代器  迭代器的游标问题
        /**
         * 这种情况下不允许对元素进行修改和删除
         *
         * 其实不止是这种情况 在遍历的情况下 逻辑上都允许修改和删除的产生
         */
        Iterator<String> it = list.iterator();
        // it.hasNext():判断下一个节点是否有元素
        while (it.hasNext()){
            //  it.next() :取出当前位置的元素
            String val = it.next();
            System.out.println("通过迭代器取出来的值:"+val);
        }
​
        System.out.println("------------------------------");
​
        //第五种遍历方式
        ListIterator<String> it1 = list.listIterator();
        while (it1.hasNext()){
            String next = it1.next();
            System.out.println("通过迭代器取出来的值:"+next);
        }
    }
}
3.1.2、LinkedList
复制代码
LinkedList底层是链表 
​
链表中包含 一个一个的链条   每一个链条都包含了两部分
​
当前节点的值  和 下一个元素的地址
​
链表中 数据存储的地址空间不连续  所以不能使用偏移量来访问

输出的值是连续的。

复制代码
public class LinkedListTest01 {
​
    public static void main(String[] args) {
        //申明对象
        List<String> linkedList1 = new LinkedList<>();
        linkedList1.add("001");
        linkedList1.add("002");
        linkedList1.add("003");
        linkedList1.add("004");
​
        for (int i = 0; i < linkedList1.size(); i++) {
            String val = linkedList1.get(i);
            System.out.println("val:"+val);
        }
        for (String val:linkedList1){
            System.out.println("val:"+val);
        }
​
        linkedList1.stream().forEach(val->{
            System.out.println("val:"+val);
        });
    }
}
​
3.1.3、Vector的使用(不常用)
复制代码
这个底层也是数组  线程安全的  效率不高
​
这个集合基本不使用 不也用记住
复制代码
public class VectorTest {
    public static void main(String[] args){
        List<String> vector=new Vector<>();
        vector.add("中国好");
        vector.add("小日子");
        for (int i = 0; i <vector.size() ; i++) {
            System.out.println("数据是:"+vector.get(i));
        }
​
    }
}
3.1.4、Stack(栈)
复制代码
public class StackTest {
​
   public static void main(String[] args){
    //这个其实是栈的数据结构
​
      Stack<String> list=new Stack<String>();
      list.push("1");
      list.push("2");
      list.push("3");
      list.push("4");
      list.push("5");
​
      System.out.println("pop:"+list.pop());
      System.out.println("pop:"+list.pop());
      System.out.println("pop:"+list.pop());
      System.out.println("pop:"+list.pop());
      System.out.println("pop:"+list.pop());
​
   }
}
3.2、Set集合
复制代码
逻辑上 Set集合逻辑上是无序的  而且Set集合能排重  不能通过下标直接访问

Set<E> 的爹 依然是Collection   

Set这个接口是所有Set集合的爹

Set排重的原则是啥?
  如果在Set集合中存放的是对象比如User 那么他就首先会去调用这个User中的 hashCode方法 然后获取到当前的这个要添加数据的hashCode值去和已经添加数据的HashCode值 做比较 如果是不等 那么说明肯定不是一个元素 那么直接添加元素  如果是HashCode值 遇到了在已经添加的数据中的HashCode值是相等的话 那么都说明有可能这个值是重复的 如果是这个值是重复的话 那就去调用当前这个对象的equals方法 判断equals方法是不是返回true  如果返回true 那么说明值重复  不添加数据  如果返回的是false  那么说明值 不重复 那么就可以添加数据
3.2.1、Set集合的排重问题(HashSet)
复制代码
 public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("123");
        set.add("345");
        set.add("234");
        set.add("345");
        System.out.println("数据的个数:" + set.size());
        System.out.println("-----------------------------");
        Set<User> setUser = new HashSet<>();
        setUser.add(new User(1, "小小", "112"));
        setUser.add(new User(1, "小小", "134"));
        setUser.add(new User(1, "小小", "165"));
        setUser.add(new User(1, "小小", "178"));
        System.out.println("数据的个数:" + setUser.size());
    }
复制代码
public class User {
    private Integer id;
    private String username;
    private String password;
​
    public User(Integer id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }
​
    public User() {
    }
​
    public Integer getId() {
        return id;
    }
​
    public void setId(Integer id) {
        this.id = id;
    }
​
    public String getUsername() {
        return username;
    }
​
    public void setUsername(String username) {
        this.username = username;
    }
​
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
​
    @Override
    public int hashCode() {
        return this.username.hashCode();
    }
​
    /**
     * 用户名一样 那么我们就认为这是同一个数据
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj) {
        if(obj instanceof User){
            User user= (User) obj;
            return this.username.equals(user.getUsername());
        }
        return false;
    }
}
3.2.2、Set集合的遍历问题(HashSet)
复制代码
public class HashSetTest1 {
​
    public static void main(String[] args) {
        Set<User> set = new HashSet<>();
        set.add(new User(1,"xiaobobo","123"));
        set.add(new User(-1,"tiedan","777"));
        set.add(new User(3,"gousheng","0"));
        set.add(new User(4,"gouwa","234"));
        set.add(new User(1,"ergouzi","234"));
​
        //通过增强的for循环能访问
        for (User val:set){
            System.out.println("数据:"+val);
        }
​
        System.out.println("--------------------------");
​
        Iterator<User> it = set.iterator();
        while (it.hasNext()){
            User next = it.next();
            System.out.println("拿到的数据是:"+next);
        }
​
        System.out.println("--------------");
        
        set.stream().forEach(user -> {
            System.out.println("读取到的数据是:"+user);
        });
    }
}
​
3.2.3、LinkedHashSet的使用
复制代码
这个集合的底层是链表
​
这个集合的数据保存是有序的
复制代码
public class LinkedHashSetTest {
    public static void main(String[] args) {
        Set<User> set = new LinkedHashSet<>();
        set.add(new User(1, "xiaobobo", "123"));
        set.add(new User(-1, "tiedan", "777"));
        set.add(new User(3, "gousheng", "0"));
        set.add(new User(4, "gouwa", "234"));
        set.add(new User(1, "gouwa", "234"));
        Iterator<User> it = set.iterator();
        while (it.hasNext()) {
            User next = it.next();
            System.out.println(next);
        }
    }
}
3.2.4、TreeSet(底层实现是红黑树)
复制代码
TreeSet和其他的Set集合一样 具有 排重的特性
​
TreeSet的底层是红黑树--->二叉树--->数据结构--->有大小关系
​
TreeSet集合自动具有排序的功能
​
这个排序 就涉及到一个大小的问题
​
自然数的大小  
​
字符串如何比较大小呢?  unicode编码值
3.2.5、两个字符串如何比较大小呢?通过编码
复制代码
// 在String这个类中为我们提供了这个比较两个字符串大小的方法 
public static void main(String[] args) {
        String str = "Ab";
        String str2 = "Ab";
        /**
         * 返回值 0:表示的是前后相等
         * 返回值-1:表示的是前面小于后面
         * 返回值是1:表示的是前面大于后面
         */
        System.out.println(str2.compareTo(str));
}
3.2.6、TreeSet的使用
复制代码
TreeSet的底层使用的是红黑树来实现的
3.2.6.1、TreeSet的基本使用
复制代码
package com.qfedu.edu.collection.set;
​
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
​
​
public class TreeSetTest {
​
    public static void main(String[] args) {
        Set<Integer> set = new TreeSet<>();
        set.add(123);
        set.add(0);
        set.add(345);
        set.add(77);
        set.add(77);
        set.add(89);
​
        //遍历这些数据
        Iterator<Integer> it = set.iterator();
​
        while (it.hasNext()) {
            Integer next = it.next();
            System.out.println("数据是:" + next);
        }
​
        //--------------下面研究字符串的排序------------
        System.out.println("-------------------");
​
        Set<String> setStr = new TreeSet<>();
        setStr.add("Abc");
        setStr.add("Bc");
        setStr.add("Ac");
​
        //遍历这些数据
        Iterator<String> it1 = setStr.iterator();
​
        while (it1.hasNext()) {
            String next = it1.next();
            System.out.println("数据是:" + next);
        }
​
    }
}
​
3.2.6.2、Comparable接口实现对象的比较

1、编写Employee对象

复制代码
public class Employee implements Comparable<Employee>{
​
    private Integer id;
    private String name;
    private Integer salary;
    private String address;
​
    public Employee(Integer id, String name, Integer salary, String address) {
        this.id = id;
        this.name = name;
        this.salary = salary;
        this.address = address;
    }
​
    public Employee() {
    }
​
    public Integer getId() {
        return id;
    }
​
    public void setId(Integer id) {
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public Integer getSalary() {
        return salary;
    }
​
    public void setSalary(Integer salary) {
        this.salary = salary;
    }
​
    public String getAddress() {
        return address;
    }
​
    public void setAddress(String address) {
        this.address = address;
    }
​
    /**
     * 比较的方法
     *    你需要按照谁排序 那么下面你就按照什么来比较
     *
     *      我要通过薪资排序
     *         薪资是int类型 那么下面就直接做减法
     * @param o the object to be compared.
     * @return
     */
//    @Override
//    public int compareTo(Employee o) {
//        return this.salary-o.getSalary();
//    }
​
    /**
     * 下面演示通过姓名来排序
     *  姓名是字符串类型
     * @param o the object to be compared.
     * @return
     */
 /*   @Override
    public int compareTo(Employee o) {
        return this.getName().compareTo(o.getName());
    }*/
​
    /**
     * 如果薪资不为空 那么按照薪资排序
     *   如果薪资为空 并且姓名不为空 那么按照姓名排序
     *   如果姓名为空 那么就按照id排序....
     * @param o the object to be compared.
     * @return
     */
    @Override
    public int compareTo(Employee o) {
        if(o.getSalary()!=null){
            return this.getSalary()-o.getSalary();
        }else if(o.getName()!=null&&!("".equals(o.getName()))){
            return this.getName().compareTo(o.getName());
        }else{
          return this.id-o.getId();
        }
    }
​
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", salary=" + salary +
                ", address='" + address + '\'' +
                '}';
    }
}
​

2、编写测试类

复制代码
public class TreeSetTest1 {
​
    public static void main(String[] args) {
​
        Set<Employee> set = new TreeSet<>();
        set.add(new Employee(1,"xiaobobo",3500,"四川成都"));
        set.add(new Employee(2,"xiaowangzi",1800,"四川巴中"));
        set.add(new Employee(3,"tiedan",2600,"四川自贡"));
        set.add(new Employee(4,"gousheng",15000,"四川绵阳"));
        set.add(new Employee(5,"gouwa",2700,"四川德阳"));
​
​
        Iterator<Employee> iterator = set.iterator();
        while (iterator.hasNext()){
            Employee next = iterator.next();
            System.out.println("获取到的数据是:"+next);
        }
    }
}
​
3.2.6.3、使用Comparator来实现对象的排序

1、对象的编写

复制代码
public class Employee1{
​
    private Integer id;
    private String name;
    private Integer salary;
    private String address;
​
    public Employee1(Integer id, String name, Integer salary, String address) {
        this.id = id;
        this.name = name;
        this.salary = salary;
        this.address = address;
    }
​
    public Employee1() {
    }
​
    public Integer getId() {
        return id;
    }
​
    public void setId(Integer id) {
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public Integer getSalary() {
        return salary;
    }
​
    public void setSalary(Integer salary) {
        this.salary = salary;
    }
​
    public String getAddress() {
        return address;
    }
​
    public void setAddress(String address) {
        this.address = address;
    }
​
​
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", salary=" + salary +
                ", address='" + address + '\'' +
                '}';
    }
}
​

2、测试的编写

复制代码
package com.qfedu.edu.collection.set;
​
import com.qfedu.edu.pojo.Employee;
import com.qfedu.edu.pojo.Employee1;
​
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
​
/**
 * @author xiaobobo
 * @title: TreeSetTest
 * @projectName CD-Java-JY-2401-Simple-Parent
 * @description: 这个研究下TreeSet的对象的排序问题
 * @date 2024/3/19  15:26
 */
public class TreeSetTest2 {
​
    public static void main(String[] args) {
​
        Set<Employee1> set = new TreeSet<>(new MyComparator());
        set.add(new Employee1(1,"xiaobobo",3500,"四川成都"));
        set.add(new Employee1(2,"xiaowangzi",1800,"四川巴中"));
        set.add(new Employee1(3,"tiedan",2600,"四川自贡"));
        set.add(new Employee1(4,"gousheng",15000,"四川绵阳"));
        set.add(new Employee1(5,"gouwa",2700,"四川德阳"));
​
        Iterator<Employee1> iterator = set.iterator();
        while (iterator.hasNext()){
            Employee1 next = iterator.next();
            System.out.println("获取到的数据是:"+next);
        }
​
​
    }
​
​
    /**
     * 自定义了一个比较器 这个跟上一个接口是一样的
     */
    static class MyComparator implements Comparator<Employee1>{
        /**
         *
         * @param o1 新数据
         * @param o2 老数据
         *  按照薪资排序  做减法 按照谁排序 就用谁来做比较
         * @return
         */
        @Override
        public int compare(Employee1 o1, Employee1 o2) {
            return o1.getSalary()-o2.getSalary();
        }
    }
}

4、双列的集合

相关推荐
蟾宫曲7 分钟前
Node.js 工具:在 Windows 11 中配置 Node.js 的详细步骤
windows·npm·node.js·前端工具
深海的鲸同学 luvi2 小时前
【HarmonyOS NEXT】hdc环境变量配置
linux·windows·harmonyos
老大白菜8 小时前
Windows 11 安装 Dify 完整指南 非docker环境
windows·docker·容器
ue星空12 小时前
Windbg常用命令
windows
泰勒今天不想展开16 小时前
jvm接入prometheus监控
jvm·windows·prometheus
易我数据恢复大师18 小时前
怎么设置电脑密码?Windows和Mac设置密码的方法
windows·macos·电脑
m0_7482565618 小时前
Windows 11 Web 项目常见问题解决方案
前端·windows
ladymorgana20 小时前
【运维笔记】windows 11 中提示:无法成功完成操作,因为文件包含病毒或潜在的垃圾软件。
运维·windows·笔记
yngsqq1 天前
一键打断线(根据相交点打断)——CAD c# 二次开发
windows·microsoft·c#
咸鱼桨1 天前
《庐山派从入门到...》PWM板载蜂鸣器
人工智能·windows·python·k230·庐山派