【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):将集合中的元素按照指定规则排序。
java 复制代码
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中用于统一数据类型、防止数据类型转换异常的一种机制。

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 含有泛型的类

java 复制代码
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 含有泛型的方法

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

2.3 含有泛型的接口

java 复制代码
public interface MyList<E> {
    boolean add(E e);
}

2.4 泛型的高级使用

3.1 泛型通配符 ?
java 复制代码
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 泛型的上限下限
java 复制代码
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 代码实现

java 复制代码
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接口的实现类,具有元素唯一、无序、无索引、线程不安全等特点。底层数据结构为哈希表。

java 复制代码
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,具有元素唯一、有序、无索引、线程不安全等特点。底层数据结构为哈希表+双向链表。

java 复制代码
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. 哈希值一样,内容也有可能不一样

java 复制代码
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 +
                '}';
    }
}
java 复制代码
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类的哈希算法。

java 复制代码
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通过计算元素的哈希值和比较内容来去重。

java 复制代码
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方法来实现去重。

java 复制代码
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集合框架中非常重要的知识点。

相关推荐
杨DaB4 分钟前
【SpringBoot】Swagger 接口工具
java·spring boot·后端·restful·swagger
YA3335 分钟前
java基础(九)sql基础及索引
java·开发语言·sql
桦说编程25 分钟前
方法一定要有返回值 \ o /
java·后端·函数式编程
小李是个程序1 小时前
登录与登录校验:Web安全核心解析
java·spring·web安全·jwt·cookie
David爱编程1 小时前
Java 创建线程的4种姿势,哪种才是企业级项目的最佳实践?
java·后端
hrrrrb2 小时前
【Java Web 快速入门】十一、Spring Boot 原理
java·前端·spring boot
Java微观世界2 小时前
Object核心类深度剖析
java·后端
MrSYJ2 小时前
为什么HttpSecurity会初始化创建两次
java·后端·程序员
hinotoyk2 小时前
TimeUnit源码分享
java
AAA修煤气灶刘哥3 小时前
Java+AI 驱动的体检报告智能解析:从 PDF 提取到数据落地全指南
java·人工智能·后端