[Java]单列集合

文章目录


List系列集合:添加的序列是有序(存取顺序一样)、可重复、有索引

Set序列集合:添加的序列是无序(存取顺序可能不一样)、不重复、无索引

1. Collection

1.1 方法接口

添加元素:

  • 细节1,我们向List系列集合中添加元素,那么方法永远返回true,因为List系列集合允许元素重复
  • 细节2,我们向Set系列集合中添加元素,如果元素不存在,方法返回true,表示添加成功;
    如果元素已经存在,方法返回false,表示添加失败。因为Set系列集合不允许元素重复

删除:

  • 因为Collection中定义的是共性方法,所以此时不能通过索引进行删除。只能通过元素的对象进行删除
  • 删除成功返回true,失败返回false

包含:

  • 底层是依赖 equals 方法判断是否存在的
  • 所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在javabean中,一定要重写 equals 方法


Student 类中重写的 equals 方法:

1.2 Collection的遍历方式

迭代器遍历

迭代器不依赖索引。

使用:




总结:

增强for遍历


Lambda表达式遍历

先用匿名内部类理解一下:


1.3 Collection总结

2. List

2.1 接口

例子:

2.2 List集合遍历方式

迭代器遍历
列表迭代器遍历

ListIterator就是在Iterator的基础上添加的prev系列方法,可以实现反向操作,最重要的是添加了add和set方法,可以实现遍历List的时候同时进行添加,修改的操作。

示例一:

java 复制代码
ArrayList<Character> list = new ArrayList<>();
for (char c = 'A'; c <= 'G'; c++) {
    list.add(c);
}
 
Iterator<Character> it = list.iterator();
while (it.hasNext()) {
    char c = it.next(); // next() 返回下一个元素
    if (c == 'C') {
        it.remove(); // remove() 移除元素
    } else {
        System.out.print(c + ", ");
    }
}

示例二:

java 复制代码
public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    for (int i = 1; i <= 3; i++) {
        list.add(i);
    }
    System.out.println(list); // [1, 2, 3]

    ListIterator<Integer> li = list.listIterator();
    boolean flag = true;
    // 如果是正序迭代 或者 有前一个可以迭代的元素
    while (flag || li.hasPrevious()) {
        int index = 0;
        int ele = 0;
        if (flag) {
            index = li.nextIndex();  // nextIndex() 返回下一个元素的索引
            ele = li.next();         // next() 返回下一个元素
        } else {
            index = li.previousIndex(); // previousIndex 返回上一个元素的索引
            ele = li.previous();        // previous() 返回上一个元素
        }
        if (ele == 1) {
            // 如果迭代到的元素是 1 ,则将该元素替换成 0
            li.set(0); // set() 用指定元素替换最后返回的元素
        } else if (ele == 3) {
            li.remove(); // remove() 移除最后返回的元素
        }
        System.out.println("(" + index + ") = " + ele);

        // 判断是否还有下一个可以迭代的元素
        if (!li.hasNext()) {
            flag = false;
            li.add(10); // add() 添加一个元素
        }
    }

}
java 复制代码
// 结果
[1, 2, 3]
(0) = 1
(1) = 2
(2) = 3
(2) = 10
(1) = 2
(0) = 0

ListIterator方法

增强for遍历

同上上图

Lambda表达式遍历---forEach()
普通for遍历(因为List集合存在索引)

2.3 总结

3. ArrayList

3.1 源码


3.2 迭代器源码




4. LinkedList

4.1 方法接口

不怎么用。

4.2 源码

5. Set

5.1 方法接口

仍可以用 Collection 中的:



5.2 遍历方式

迭代器遍历
增强for遍历
Lambda表达式遍历

5.3 总结

6. HashSet

6.1 哈希值


没有重写hashCode()

没有重写 hashCode(),不同对象计算出的哈希值是不同的:

重写hashCode()

重写 hashCode(),不同对象但是相同属性 计算出的哈希值是相同的:


小概率情况下发生哈希碰撞

6.2 底层原理




必须符合两个条件才会转换成红黑树:链表长度大于8,并且数组长度大于等于64。

6.3 HashSet三个问题

  • 为什么存和取顺序不一样?

HashSet 遍历的时候是从0索引开始的,一条链表一条链表的遍历。如果对应索引是红黑树则会把红黑树遍历

  • 为什么没有索引?

他不够纯粹,底层是数组、链表、红黑树三种结构组成的

  • 是利用什么机制来保证数据去重的?

hashCode()equals() 两个方法,hashCode()确认存放的位置,equals()判断内部属性值是否相同。

如果存放的是自定义类型,一定要重写这两个方法。

7. LinkedHashSet

7.1 底层原理

7.2 总结

8. TreeSet


8.1 遍历

迭代器遍历
增强for遍历
Lambda表达式遍历

8.2 排序规则


方式一:默认排序规则/自然排序

JavaBean类 实现 Comparable 接口,重写里面的抽象方法,再指定比较规则。

Student 实现 Comparable 接口,重写里面的抽象方法,再指定比较规则。


按照年龄升序排列:


方式二:比较器排序

创建 TreeSet 对象的时候,传递比较器 Comparator 制定规则。

使用原则:默认使用第一种,如果第一种不能满足当前需求,就是用第二种。

长度一样则按照原本的 compareTo 方法比较。


8.3 总结

方式一和方式二都存在,以方式二为准。

9. 总结:使用场景

相关推荐
南梦浅2 小时前
全过程步骤(从零到高可用企业网络)
开发语言·网络·php
mjhcsp2 小时前
C++ 梯度下降法(Gradient Descent):数值优化的核心迭代算法
开发语言·c++·算法
ok_hahaha2 小时前
java从头开始-黑马点评-基础篇
java·开发语言
吴声子夜歌2 小时前
JavaScript——函数
开发语言·javascript·ecmascript
yunyun321232 小时前
跨语言调用C++接口
开发语言·c++·算法
m0_518019482 小时前
C++中的装饰器模式变体
开发语言·c++·算法
SuperEugene2 小时前
Vue3 + Element Plus 中后台弹窗规范:开闭、传参、回调,告别弹窗地狱|Vue 组件与模板规范篇
开发语言·前端·javascript·vue.js·前端框架
SuperEugene2 小时前
VXE-Table 4.x 实战规范:列配置 + 合并单元格 + 虚拟滚动,避坑卡顿 / 错乱 / 合并失效|表单与表格规范篇
开发语言·前端·javascript·vue.js·前端框架·vxetable
xushichao19892 小时前
高性能密码学库
开发语言·c++·算法