当前位置: 首页 > article >正文

【day20】集合深入探讨

模块19回顾

在深入探讨模块20之前,让我们回顾一下day19中的关键内容:

  1. Collection集合:单列集合的顶级接口,提供了addaddAllclearsizeisEmptyremovetoArraycontains等方法。
  2. 迭代器(Iterator):通过iterator方法获取,提供了hasNext()next()方法。在迭代集合时,不能随意修改集合长度,否则会抛出并发修改异常。
  3. 数据结构:栈(先进后出)、队列(先进先出)、数组(查询快,增删慢)、链表(查询慢,增删快)。
  4. ArrayList:特点包括元素有序、有索引、元素可重复、线程不安全。底层数据结构为数组,提供了addadd(index, element)removesizegetset等方法。自动扩容机制,扩容1.5倍。
  5. LinkedList:特点包括元素有序、有索引(通过方法支持,非本质索引)、元素可重复、线程不安全。底层数据结构为双向链表,提供了大量直接操作首尾元素的方法。
  6. 增强for循环:格式为for(元素类型 变量名:集合名或者数组名),遍历集合时使用迭代器,遍历数组时使用普通for循环。

模块20重点

本模块将深入探讨集合的高级应用,包括:

  1. 掌握Collections集合工具类的常用方法。
  2. 掌握泛型的使用。
  3. 了解HashSetLinkedHashSet的特点及使用。
  4. 了解HashSet将元素去重的过程。

第一章:Collections集合工具类

Collections是一个集合工具类,提供了多种静态方法来操作集合。

  • static <T> boolean addAll(Collection<? super T> c, T... elements):批量添加元素。
  • static void shuffle(List<?> list):将集合中的元素顺序打乱。
  • static <T> void sort(List<T> list):将集合中的元素按照默认规则排序。
  • static <T> void sort(List<T> list, Comparator<? super T> c):将集合中的元素按照指定规则排序。
public class Demo01Collections {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张三", "李四", "王五", "赵六", "田七", "朱八");
        System.out.println(list);
        Collections.shuffle(list);
        System.out.println(list);
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("c.举头望明月");
        list1.add("a.床前明月光");
        list1.add("d.低头思故乡");
        list1.add("b.疑是地上霜");
        Collections.sort(list1);
        System.out.println(list1);
    }
}

第二章:泛型

泛型是Java中用于统一数据类型、防止数据类型转换异常的一种机制。

public class Demo01Genericity {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("1");
        list.add(1);
        list.add("abc");
        list.add(2.5);
        list.add(true);

        for (Object o : list) {
            String s = (String) o;
            System.out.println(s.length());
        }
    }
}

2.1 含有泛型的类

public class MyArrayList<E> {
    Object[] obj = new Object[10];
    int size;

    public boolean add(E e) {
        obj[size] = e;
        size++;
        return true;
    }

    public E get(int index) {
        return (E) obj[index];
    }

    @Override
    public String toString() {
        return Arrays.toString(obj);
    }
}

2.2 含有泛型的方法

public class ListUtils {
    public static <E> void addAll(ArrayList<E> list, E... e) {
        for (E element : e) {
            list.add(element);
        }
    }
}

2.3 含有泛型的接口

public interface MyList<E> {
    boolean add(E e);
}

2.4 泛型的高级使用

3.1 泛型通配符 ?
public class Demo01Genericity {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("张三");
        list1.add("李四");

        ArrayList<Integer> list2 = new ArrayList<>();
        list2.add(1);
        list2.add(2);
        
        method(list1);
        method(list2);
    }
    
    public static void method(ArrayList<?> list) {
        for (Object o : list) {
            System.out.println(o);
        }
    }
}
3.2 泛型的上限下限
public class Demo02Genericity {
    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<>();
        ArrayList<String> list2 = new ArrayList<>();
        ArrayList<Number> list3 = new ArrayList<>();
        ArrayList<Object> list4 = new ArrayList<>();

        get1(list1);
        //get1(list2);错误
        get1(list3);
        //get1(list4);错误

        System.out.println("=================");

        //get2(list1);错误
        //get2(list2);错误
        get2(list3);
        get2(list4);
    }

    public static void get1(Collection<? extends Number> collection) {

    }

    public static void get2(Collection<? super Number> collection) {

    }
}

第三章:斗地主案例(扩展案例)

3.1 案例介绍

按照斗地主的规则,完成洗牌发牌的动作。具体规则:使用54张牌打乱顺序,三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。

3.2 案例分析

  • 准备牌:牌可以设计为一个ArrayList<String>,每张牌由花色数字两部分组成,使用Collections类的shuffle方法进行随机排序。
  • 发牌:将每个人以及底牌设计为ArrayList<String>,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。
  • 看牌:直接打印每个集合。

在这里插入图片描述

3.3 代码实现

public class Poker {
    public static void main(String[] args) {
        ArrayList<String> color = new ArrayList<>();
        ArrayList<String> number = new ArrayList<>();
        ArrayList<String> poker = new ArrayList<>();

        color.add("♠");
        color.add("♥");
        color.add("♣");
        color.add("♦");

        for (int i = 2; i <= 10; i++) {
            number.add(i + "");
        }

        number.add("J");
        number.add("Q");
        number.add("K");
        number.add("A");

        for (String num : number) {
            for (String huaSe : color) {
                String pokerNumber = huaSe + num;
                poker.add(pokerNumber);
            }
        }

        poker.add("😊");
        poker.add("☺");

        Collections.shuffle(poker);

        ArrayList<String> p1 = new ArrayList<>();
        ArrayList<String> p2 = new ArrayList<>();
        ArrayList<String> p3 = new ArrayList<>();
        ArrayList<String> dipai = new ArrayList<>();
        for (int i = 0; i < poker.size(); i++) {
            String s = poker.get(i);
            if (i >= 51) {
                dipai.add(s);
            } else if (i % 3 == 0) {
                p1.add(s);
            } else if (i % 3 == 1) {
                p2.add(s);
            } else if (i % 3 == 2) {
                p3.add(s);
            }
        }

        System.out.println("涛哥:" + p1);
        System.out.println("三上:" + p2);
        System.out.println("金莲:" + p3);
        System.out.println("底牌:" + dipai);
    }
}

第四章:红黑树(了解)

集合加入红黑树的目的:提高查询效率。HashSet集合的数据结构包括哈希表,其中JDK8之前为数组+链表,JDK8之后为数组+链表+红黑树,以提高查询效率。
在这里插入图片描述

  1. 每一个节点或是红色的,或者是黑色的

  2. 根节点必须是黑色

  3. 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的

  4. 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连 的情况)

  5. 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点

在这里插入图片描述
https://www.cs.usfca.edu/~galles/visualization/RedBlack

第五章:Set集合

Set接口并没有对Collection接口进行功能上的扩充,而且所有的Set集合底层都是依靠Map实现
在这里插入图片描述

1.Set集合介绍

SetMap密切相关,Map的遍历需要先变成单列集合,只能变成Set集合。

2.HashSet集合的介绍和使用

HashSetSet接口的实现类,具有元素唯一、无序、无索引、线程不安全等特点。底层数据结构为哈希表。

public class Demo01HashSet {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("赵六");
        set.add("田七");
        set.add("张三");
        System.out.println(set);

        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        for (String s : set) {
            System.out.println(s);
        }
    }
}

3.LinkedHashSet的介绍以及使用

LinkedHashSet继承自HashSet,具有元素唯一、有序、无索引、线程不安全等特点。底层数据结构为哈希表+双向链表。

public class Demo02LinkedHashSet {
    public static void main(String[] args) {
        LinkedHashSet<String> set = new LinkedHashSet<>();
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("赵六");
        set.add("田七");
        set.add("张三");
        System.out.println(set);

        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        for (String s : set) {
            System.out.println(s);
        }
    }
}

4.哈希值

哈希值是由计算机算出来的一个十进制数,可以看做是对象的地址值。获取对象的哈希值使用的是Object中的方法public native int hashCode()

注意:
a. 哈希值不一样,内容肯定不一样
b. 哈希值一样,内容也有可能不一样

public class Person {
    private String name;
    private Integer age;

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

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Demo01Hash {
    public static void main(String[] args) {
        Person p1 = new Person("涛哥", 18);
        Person p2 = new Person("涛哥", 18);
        System.out.println(p1);
        System.out.println(p2);

        System.out.println(p1.hashCode());
        System.out.println(p2.hashCode());
    }
}

5.字符串的哈希值是如何算出来的

字符串的哈希值是通过特定的算法计算出来的,例如String类的哈希算法。

public int hashCode() {
    int h = hash;
    if (h == 0 && !hashIsZero) {
        h = isLatin1() ? StringLatin1.hashCode(value)
                       : StringUTF16.hashCode(value);
        if (h == 0) {
            hashIsZero = true;
        } else {
            hash = h;
        }
    }
    return h;
}

6.HashSet的存储去重复的过程

HashSet通过计算元素的哈希值和比较内容来去重。

public class Test02 {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("abc");
        set.add("通话");
        set.add("重地");
        set.add("abc");
        System.out.println(set);
    }
}

7.HashSet存储自定义类型如何去重复

自定义类型需要重写hashCodeequals方法来实现去重。

public class Person {
    private String name;
    private Integer age;

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

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

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

public class Test03 {
    public static void main(String[] args) {
        HashSet<Person> set = new HashSet<>();
        set.add(new Person("涛哥", 16));
        set.add(new Person("金莲", 24));
        set.add(new Person("涛哥", 16));
        System.out.println(set);
    }
}

小结

通过本文的学习,希望能够帮助您深入理解集合的高级应用,包括Collections集合工具类的常用方法、泛型的使用、HashSetLinkedHashSet的特点及使用,以及HashSet将元素去重的过程。这些都是Java集合框架中非常重要的知识点。


http://www.kler.cn/a/458873.html

相关文章:

  • Django-Easy-Audit 实战:轻松实现数据审计
  • 人工智能(AI)简史:推动新时代的科技力量
  • Windows安装Confluence详解
  • el-input输入框需要支持多输入,最后传输给后台的字段值以逗号分割
  • 【JS】期约的Promise.all()和 Promise.race()区别
  • 常用的linux命令介绍
  • Optional类:避免NullPointerException
  • Go语言的字符串处理
  • 每天40分玩转Django:Django Channels
  • react-native键盘遮盖底部输入框问题修复
  • 对于多个网站的爬虫管理和配置支持
  • 前端处理跨域的几种方式
  • AI 加持下的智能家居行业:变革、挑战与机遇
  • 深度学习-78-大模型量化之Quantization Aware Training量化感知训练QAT
  • LeetCode每日三题(五)双指针
  • 基于PLC的电梯控制系统(论文+源码)
  • 从Huggingface下载的数据集为arrow格式,如何从本地路径读取arrow数据并输出样例
  • Knowledge is power——Digital Electronics
  • pytorch基础之注解的使用--003
  • 「Mac玩转仓颉内测版55」应用篇2 - 使用函数实现更复杂的计算
  • 项目优化性能监控
  • 基于YOLOv10和BYTETracker的多目标追踪系统,实现地铁人流量计数功能(基于复杂场景和密集遮挡条件下)
  • 前端学习DAY29(1688侧边栏)
  • NPM组件包 vant部分版本内嵌挖矿代码
  • 《燕云十六声》d3dcompiler_47.dll缺失怎么解决?
  • 深度学习中的HTTP:从请求到响应的计算机网络交互