Java 进阶集合Set、Map(二)

简介: Java 进阶集合Set、Map

一、Set集合

1、HashSet集合

1)原理

底层采用哈希表存储数据

2)组成

jdk8之前:底层数组+链表组成

jdk8之后:底层数组+链表+红黑树组成

3)哈希值

对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。更重要的是:这里的内存地址是JVM虚拟机虚拟出来的地址,并不是真实的物理内存地址

4)哈希值特点

同一个对象多次调用hashCode()方法返回的哈希值是相同的

默认情况下,不同对象的哈希值是不同的

5)jdk8哈希表流程:

Constructs a new, empty set; the backing HashMap instance has default initial capacity (16) and load factor (0.75).

创建一个新的空集合,默认初始值是16,加载因子(0.75)

根据元素的哈希值和数组的长度计算出应存入的位置

首先判断当前位置是否为NULL,空则直接存入,非空则equals方法比较属性值,相同则不存,不同则存入数组

当数组存储满足16*0.75=12时自动扩容,每次扩容会是当前容量的2倍

d08ba0f00ece82d72bfbbbe476d38ed.png

import java.util.HashSet;
public class ClassStructure {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("aa");
        set.add("bb");
        set.add("cc");
        set.add("aa");
        set.add("ee");
        set.add("ff1");
        set.add("ff2");
        set.add("ff3");
        System.out.println(set);
        //哈希值
        System.out.println(set.hashCode());
    }
}

2、LinkedHashSet集合

1)概述

有序、不重复、无索引

有序指保证存储和取出元素顺序一致

2)原理

底层数据结构哈希表,每个元素增加双链表机制记录数据存储顺序

5b8aed8a9ea8b87fb843eb8aea7be1e.png

f16520370cfd8f03e6252ee5df3f9cc.png

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class ClassStructure {
    public static void main(String[] args) {
        Set set = new LinkedHashSet<>();
        set.add("aa");
        set.add(123);
        set.add(456);
        set.add("hello");
        System.out.println(set);
    }
}

3、TreeSet集合

不重复、无索引、可排序

可排序:按照元素的大小默认升序(有小到大)排序。

TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好。

注意:TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序

1)默认规则

对于数值类型:Integer , Double,默认升序排序。

对于字符串类型:默认按照首字符的编号升序排序。

对于自定义类型对象,TreeSet无法直接排序。

2) 自定义规则

TreeSet集合有参数构造器,可以设置Comparator接口对应的比较器对象,来定制比较规则。

eef540d8eb5a1d4b121cc4576c0529e.png

public class Student {
    private int id;
    private String name;
    private int age;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    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{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class ClassStructure {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.setId(1);
        stu.setName("zhangsan");
        stu.setAge(11);
        Student stu1 = new Student();
        stu1.setId(3);
        stu1.setName("zhangsan3");
        stu1.setAge(33);
        Student stu2 = new Student();
        stu2.setId(2);
        stu2.setName("zhangsan2");
        stu2.setAge(22);
        Student stu3 = new Student();
        stu3.setId(5);
        stu3.setName("zhangsan5");
        stu3.setAge(55);
        Set<Student> set = new TreeSet<>(
                new Comparator<Student>() {
                    @Override
                    public int compare(Student o1, Student o2) {
                        return o1.getId()-o2.getId();
                    }
                }
        );
        set.add(stu);
        set.add(stu1);
        set.add(stu2);
        set.add(stu3);
        for (Student id:set){
            System.out.println(id);
        }
    }
}

让自定义的类,实现Comparable接口重写里面的compareTo方法来定制比较规则。

99f6137de347a0b2db25d21fea37094.png

public class Student implements Comparable<Student>{
    private int id;
    private String name;
    private int age;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    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{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    /*
    默认升序
     */
    @Override
    public int compareTo(Student o) {
        return this.id - o.id;
    }
}
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class ClassStructure {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.setId(1);
        stu.setName("zhangsan");
        stu.setAge(11);
        Student stu1 = new Student();
        stu1.setId(3);
        stu1.setName("zhangsan3");
        stu1.setAge(33);
        Student stu2 = new Student();
        stu2.setId(2);
        stu2.setName("zhangsan2");
        stu2.setAge(22);
        Student stu3 = new Student();
        stu3.setId(5);
        stu3.setName("zhangsan5");
        stu3.setAge(55);
        Set<Student> set = new TreeSet<>();
        set.add(stu);
        set.add(stu1);
        set.add(stu2);
        set.add(stu3);
        for (Student id:set){
            System.out.println(id);
        }
    }
}

4、可变参数(动参)

定义

可变参数用在形参中可以接收多个数据。

可变参数的格式:数据类型…参数名称

作用

接收参数非常灵活,方便。可以不接收参数,可以接收1个或者多个参数,也可以接收一个数组

可变参数在方法内部本质上就是一个数组。

注意

一个形参列表中可变参数只能有一个

可变参数必须放在形参列表的最后面

题目(实战),需求:

假如需要定义一个方法求和,该方法可以灵活的完成如下需求:

计算1个数据的和。

计算2个数据的和。

计算3个数据的和。

计算n个数据的和,甚至可以支持不接收参数进行调用。

7279934d79e860112a487a469344ae8.png

public class ClassSructure {
    public static void Test(Integer... args) {
        int sum = 0;
        for (int ag : args) {
            sum += ag;
        }
        System.out.println(sum);
    }
    public static void main(String[] args) {
        Test(1);
        Test(1, 2);
        Test(1, 2, 3);
    }
}

二、Map集合

1、概述

Map是双列集合,每个元素包含两个数据,格式(Key=Value),也称为键值对集合

2、特点

Map集合的键是无序,不重复的,无索引的,值不做要求(可以重复)

Map集合后面重复的键对应的值会覆盖前面重复键的值,键值对都可以为null。

3、常用API

方法名 解释

V put(K key,V value) 添加元素

V remove(Object key) 根据键删除键值对元素

void clear() 清空所有的键值对元素

int size() 集合的长度,集合中键值对的个数

boolean containsKey(Object key) 判断集合是否包含指定的键

boolean containsValue(Object value) 判断集合是否包含指定的值

boolean isEmpty() 判断集合是否为空

4、HashMap 用的最多

元素按照键是无序,不重复,无索引,值不做要求(可以重复)

-实战根据key求value

038603882c73357e7416247870f2711.png

import java.util.HashMap;
import java.util.Map;
public class ClassStructure {
    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"数学");
        map.put(2,"语文");
        map.put(3,"英语");
        map.put(4,"物理");
        map.put(5,"政治");
        String str = map.get(1);
        System.out.println(str);
        String str1 = map.get(3);
        System.out.println(str1);
    }
}

5、LinkedHashMap

元素按照键是有序,不重复,无索引,值不做要求

实战 判断key是否存在

f0669cc8cc59d8a55ee4142620c0af5.png

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class ClassStructure {
    public static void main(String[] args) {
        Map<Integer,String> map = new LinkedHashMap<>();
        map.put(1,"数学");
        map.put(2,"语文");
        map.put(3,"英语");
        map.put(4,"物理");
        map.put(5,"政治");
        boolean str = map.containsKey(1);
        System.out.println(str);
        boolean str1 = map.containsKey(6);
        System.out.println(str1);
    }
}

6、TreeMap

元素按照建是排序,不重复,无索引的,值不做要求

实战 参考TreeSet

Set系列集合的底层就是Map实现的,只是Set集合中的元素只要键数据


相关文章
|
5天前
|
Java 大数据 API
Java Stream API:现代集合处理与函数式编程
Java Stream API:现代集合处理与函数式编程
164 100
|
5天前
|
Java API 数据处理
Java Stream API:现代集合处理新方式
Java Stream API:现代集合处理新方式
157 101
|
18天前
|
算法 Java
50道java集合面试题
50道 java 集合面试题
|
9天前
|
存储 Java Go
对比Java学习Go——函数、集合和OOP
Go语言的函数支持声明与调用,具备多返回值、命名返回值等特性,结合`func`关键字与类型后置语法,使函数定义简洁直观。函数可作为一等公民传递、赋值或作为参数,支持匿名函数与闭包。Go通过组合与接口实现面向对象编程,结构体定义数据,方法定义行为,接口实现多态,体现了Go语言的简洁与高效设计。
|
1月前
|
存储 NoSQL Java
Java Stream API:集合操作与并行处理
Stream API 是 Java 8 提供的集合处理工具,通过声明式编程简化数据操作。它支持链式调用、延迟执行和并行处理,能够高效实现过滤、转换、聚合等操作,提升代码可读性和性能。
|
2月前
|
存储 缓存 JavaScript
Set和Map有什么区别?
Set和Map有什么区别?
250 1
|
3月前
|
存储 JavaScript 前端开发
for...of循环在遍历Set和Map时的注意事项有哪些?
for...of循环在遍历Set和Map时的注意事项有哪些?
257 121
|
6月前
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
172 2
|
3月前
|
存储 C++ 容器
unordered_set、unordered_multiset、unordered_map、unordered_multimap的介绍及使用
unordered_set是不按特定顺序存储键值的关联式容器,其允许通过键值快速的索引到对应的元素。在unordered_set中,元素的值同时也是唯一地标识它的key。在内部,unordered_set中的元素没有按照任何特定的顺序排序,为了能在常数范围内找到指定的key,unordered_set将相同哈希值的键值放在相同的桶中。unordered_set容器通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭代方面效率较低。它的迭代器至少是前向迭代器。前向迭代器的特性。
182 0