8.集合进阶(一)

java.util包下的常用API-集合

一、集合体系概述
1.集合概念详解
  • 是一种容器,用来装数据的,类似于数组,但集合的大小可变,开发中也非常常用
  • 集合中存储的是元素对象的地址
Collection
单列集合
value1
value2
Map
双列集合
key1,value1
key2,value2
  • Collection代表单列集合,每个元素(数据)只包含一个值
  • Map代表双列集合,每个元素包含两个值(键值对[key,value])
2.Collection集合体系
2.1 Collection体系

image-20231223222223800

2.2 Collection集合特点
  • List系列集合:添加的元素是 有序、可重复、有索引

    • 遍历方式:迭代器Iterator、增强for循环、Lambda表达式>forEach()、普通for循环
    • ArrayList、LinkedList:有序、可重复、有索引
  • Set系列集合:添加的元素是 无序、不重复、无索引

    • 遍历方式:迭代器Iterator、增强for循环、Lambda表达式>forEach()
    • HashSet:无序、不重复、无索引
    • LinkedHashSet:有序、不重复、无索引
    • TreeSet:按照大小默认升序排列、不重复、无索引

有序、无序 指的是元素存取的顺序

二、Collection的常用用法

Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的

1.Collection常见方法
方法名说明
public boolean add(E e)把给定的对象添加到集合中
public void clear()清空集合中所有的元素
public boolean remove(E e)把给定的对象在当前集合中删除
public boolean contains(Object obj)判断当前集合中是否包含给定的对象
public boolean isEmpty()判断当前集合是否为空
public int size()返回集合中元素的个数
public Object[] toArray()把集合中的元素,存储到数组中
2.Collection的遍历方法
2.1 迭代器

迭代器是用来遍历集合的专用方式(数组没有迭代器),在Java中迭代器的代表是Iterator

  • Collection集合获取迭代器的方法

    方法名称说明
    Iterator iterator()返回集合中的迭代器对象,该迭代器对象默认指向当前集合的第一个元素
  • Itreator迭代器中的常用方法

    方法名称说明
    boolean hasNext()询问当前位置是否有元素存在,存在返回true,不存在返回false
    E next()获取当前位置的元素,并同时将迭代器对象指向下一个元素处
Iterator<String> it = list.iterator();
while(it.hasNext()){
    String ele = it.next();
    System.out.println(ele);
}
2.2 增强for循环

for(元素数据类型 变量名: 数组或集合){

​ …

}

  • 增强for可以用来遍历集合或者数组
  • 增强for遍历集合,本质是迭代器遍历集合的简化写法
Collection<String> c = new ArrayList<>();
...
for (String s: c){
    System.out.println(s);
}
2.3 Lambda表达式
方法名称说明
default void forEach(Consumer<? super T> action)结合Lambda遍历集合
Collection<String> lists = new ArrayList<>();
...
lists.forEach(new Consumer<String>(){
    @override
    public void accept(String s){
        System.out.println(s);
    }
});
//简化后
lists.forEach(s -> System.out.println(s));
3.案例Demo
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.Consumer;

public class CollectionDemo1 {
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<>();
        c.add("张三");
        c.add("李四");
        c.add("王五");
        //建立一个 迭代器
        Iterator<String> it = c.iterator();
        //使用迭代器遍历输出集合中的元素
        while (it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("==========");
        //增强for循环
        for (String s : c) {//本质是一个 迭代器,底层是 普通for 循环
            System.out.println(s);
        }
        System.out.println("==========");
        // forEach 遍历
        c.forEach(System.out::println);
        c.forEach(e -> System.out.println(e));
        c.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        System.out.println("==========");
        //普通for循环
        Object[] array = c.toArray();
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}
三、List集合
1.List特点、特有方法
List
ArrarList
LinkedList
1.1 List系列集合特点

有序、可重复、有索引

  • ArrayList: 有序、可重复、有索引
  • LinkedList: 有序、可重复、有索引
1.2 List集合特有方法

List集合因为支持索引,所以多了很多与索引相关的方法,当然,Collection的功能List也都继承了

方法名说明
void add(int index, E element)在此集合中的指定位置插入指定给的元素
E remove(int index)删除指定索引处的元素,返回被删除的元素
E set(int index, E element)修改指定索引处的元素,返回被修改的元素
E get(int index)返回指定索引处的元素
1.3 List集合的遍历方式
  1. 迭代器
  2. 增强for循环
  3. Lambda表达式
  4. 普通for循环(List集合有索引)
import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("赵六");
        //遍历一:迭代器
        while (list.iterator().hasNext()){
            System.out.println(list);
        }
        //遍历二:增强for循环
        for (String s: list){
            System.out.println(s);
        }
        //遍历三:forEach
       //list.forEach(s -> System.out.println(s));
        list.forEach(System.out::println);
        //遍历四:普通for循环
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}
2.ArrayList集合
2.1 ArrayList集合的底层原理
  • 基于数组实现的
  • 查询速度快,修改效率低

具体实现原理:

  1. 利用无参构造器创建的集合,会在底层创建一个默认长度0的数组
  2. 添加第一个元素时,底层会创建一个新的长度为10的数组
  3. 存满时,会扩容1.5倍
  4. 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准。
3.LinkedList集合
3.1 LinkedList集合特有的方法
方法名称说明
public void addFirst(E e)在该列表开头插入指定的元素
public void addLast(E e)将指定的元素追加到此列表的末尾
public E getFirst()返回此列表中的第一个元素
public E getLast()返回此列表中的最后一个元素
public E removeFirst()从此列表中删除并返回第一个元素
public E removeLast()从此列表中删除并返回最后一个元素
3.2 LinkedList集合应用场景
  1. 用来设计队列
  2. 用来设计
3.3 LinkedList集合的底层原理
  • 基于双链表实现的

  • 查询慢,增删相对较快,对首尾元素进行增删改查速度极快

  • 链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址

四、Set集合
1.Set集合的特点

无序:添加数据的顺序和获取出数据的顺序不一致;不重复、无索引

  • HashSet:无序、不重复、无索引
  • LinkedHashSet:有序、不重复、无索引
  • TReeSet:排序、不重复、无索引

注意:Set要用到的常用方法,基本上就是Collection提供的!!自己几乎没有额外新增一些常用功能

2.HashSet集合的底层原理

Tips:哈希值

  • 就是一个int类型的数值,Java中每个队形都有一个哈希值
  • Java中的所有队形,都可以调用Object类提供的hashCode方法,返回该对象自己的哈希值

对象哈希值的特点

  • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
  • 不同的对象,它们的哈希值一般不相同,但也有可能会相同
2.1 底层原理
  • 基于哈希表实现
  • 哈希表是一种增删改查数据,性能都较好的数据结构
2.2 哈希表
  • JDK8之前,哈希表 = 数组 + 链表
  • JDK8之后,哈希表 = 数组 + 链表 + 红黑树

红黑树:就是可以自平衡的二叉树,是一种增删改查性能都相对较好的结构【当链表长度 > 8,且数据长度 >64 时,自动将链表转成红黑树

哈希表的详细流程:

  1. 创建一个默认长度16**,默认加载因为**0.75的数组,数组名table

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

  3. 判断当前位置是否为null,如果是null直接存入,如果位置不为null,表示有元素, 则调用equals方法比较属性值,如果一样,则不存,如果不一样,则存入数组。

  4. 当数组存满到16*0.75=12时,就自动扩容,每次扩容原先的两倍

Tips:如果希望Set集合认为2个内容一样的对象是重复的,必须重写对象的hashCode()和 equals()方法

3.LinkedHashSet集合的底层原理
  • 基于哈希表(数组+链表+红黑树)实现的
  • 它的每个元素额外的多了一个双链表的机制记录它前后元素的位置
import java.util.LinkedHashSet;
public class LinkedHashDemo {
    public static void main(String[] args) {
        LinkedHashSet<String> strings = new LinkedHashSet<>();
        strings.add("张三");
        strings.add("张三");
        strings.add("李四");

        for (String s : strings) {
            System.out.println(s); //结果:张三、李四
        }
    }
}
4.TreeSet集合
4.1 TreeSet集合特点
  • 不重复、无索引、可排序(默认升序排序,按照元素的大小,由小到大排序)
4.2 TreeSet集合原理
  • 底层是基于红黑树实现的排序
4.3 TreeSet注意点
  • 对于数值类型: Integer,Double,默认按照数值本身的大小进行升序排序
  • 对于字符串类型: 默认按照首字符的编号进行升序排序
  • 对于自定义类型的对象,TreeSet默认是无法直接排序的
4.4 TreeSet集合自定义排序规则

TreeSet集合存储自定义类型的对象时,必须指定排序规则,支持如下两种方式来指定比较规则

  1. 方式一
  • 让自定义的类实现Comparator接口,重写里面的compareTo方法来指定比较规则
  1. 方式二
  • 通过调用TreeSet集合有参构造器,可以设置Comparator对象(比较器对象,用于指定比较规则)

两种方式中,关于返回值的规则:

  • 如果认为第一个元素 > 第二个元素 返回正整数即可。

  • 如果认为第一个元素 < 第二个元素返回负整数即可。

  • 如果认为第一个元素 = 第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复

注意如果类本身有实现Comparable接口,*TreeSet集合同时也自带比较器,默认使用集合自带的比较器排序。

package d6_set;
/*
TReeSet: [在对Java中的引用类型对象进行比较的时候,该引用类型对象实现Comparable接口【自然排序】]
    在对自定义对象进行排序的时候,不需要重写hasCode,equals方法,需要借助【比较器/自然排序】
 */
import java.util.TreeSet;
public class TreeStuDemo {
    public static void main(String[] args) {
        //定义 TreeSet,按照Student的年龄降序进行排序
        TreeSet<Student1> stu = new TreeSet<>(((o1, o2) -> o2.getAge()-o1.getAge()));
        stu.add(new Student1("张三",12));
        stu.add(new Student1("李四",23));
        stu.add(new Student1("张三",12));
        for (Student1 s : stu) {
            System.out.println(s); //结果: 李四 23;张三 12
        }
    }
}
class Student1 {
    private String name;
    private int age;
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    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 Student1(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Student1() {
    }
}
五、总结Tips
  1. 如果希望记住元素的添加顺序,需要存储重复的元素,又要频繁的根据索引查询数据
ArrayList集合(有序、可重复、有索引),底层基于数组的。(常用)
  1. 如果希望记住元素的添加顺序,且增删首尾数据的情况较多
LinkedList集合(有序、可重复、有索引),底层基于双链表实现的
  1. 如果不在意元素顺序,也没有重复元素需要存储,只希望增删改查都快
HashSet集合(无序,不重复,无索引),底层基于哈希表实现的。 (常用)
  1. 如果希望记住元素的添加顺序,也没有重复元素需要存储,且希望增删改查都快
LinkedHashSet集合(有序,不重复,无索引), 底层基于哈希表和双链表
  1. 如果要对元素进行排序,也没有重复元素需要存储?且希望增删改查都快
TreeSet集合,基于红黑树实现
六、注意事项:集合的并发修改异常问题
  • 使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误
  • 由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删除集合中的数据时,程序也会出现并发修改异常的错误

保证遍历集合同时删除数据时不出bug两种方式:

  • 使用迭代器遍历集合,但用迭代器自己的删除方法删除数据即可
  • 如果能用for循环遍历时:可以倒着遍历并删除;或者从前往后遍历,但删除元素后做i --操作
  • 28
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值