集合的概念
集合:就是用来存放数据的一个容器
集合与数组的比较
为什么需要集合
-
数组
- 长度是固定的,不能再去添加元素
int[] a = {10, 20, 30}; a[3] = 0;//报错,数组越界
-
集合类
- 长度可以改变
- 能存储任意的对象
- 长度是随着元素的增加而增加
集合与数组的区别
- 数组能存基本数据类型 和 引用数据类型
- 集合当中只能存引用数据类型(对象),也可存放基本数据类型(本质是 自动装箱)
- 数组的长度是固定的,集合的长度可以改变
集合与数组的适用场合
- 如果元素个数是固定的,推荐使用数组
- 如果元素不固定,推荐使用集合
集合的集成体系
- Collection接口(父接口)
- List接口(有序)
- ArrayList实现类(数组)
- LinkedList实现类(链表)
- Vector实现类(数组)
- Set接口(无序)
- HashSet实现类(hash算法)
- TreeSet实现类(二叉树)
- List接口(有序)
继承关系图
Collection
Collection的特点
List
可以添加重复元素,而Set
不能添加重复元素(如果添加重复时,其返回值为false
)- 可以添加基本数据类型(自动装箱)
- 添加任何对象
- 打印直接得到内容(
List
内部覆盖toString()
)
Collection的常用方法
add(元素)
:追加对象,其返回值永远是true
remove(元素)
:移除指定的元素size()
:判断集合的长度(有几个元素)clear()
:清空集合isEmpty()
:验证集合是否为空
与all相关的常用方法
集合.addAll(集合)
:拼接集合
//c1是[a, b, c]
//c2是[a, b, c]
c1.addAll(c2)//[a, b, c, a, b, c]
集合.removeAll(集合)
:删除两个集合的交集集合.containsAll(集合)
:判断调用的集合是否包含(全部包含) 传入的集合- 返回值:全部包含,
true
;未全部包含,false
- 返回值:全部包含,
集合1.retainAll(集合2)
:取交集,把交集结果给 集合1- 返回值:如果改变,
true
;如果未变,false
- 返回值:如果改变,
集合的遍历
数组形式的遍历
- 先把集合转换成数组
- 然后遍历数组
元素为基本数据类型
元素为对象
向上转型(向根类转型):数组里的元素都是Object
类型
迭代器
迭代器常用方法
- 创建迭代器:
集合.iterator()
- 返回值:迭代器对象
- 示例:
Iterator it = c1.iterator();
- 获取元素:
迭代器.next()
- 返回值:获取当前游标的内容,游标并往后移动一位
- 示例:
Object o = it.next();
- 判断迭代器是否还有元素:
迭代器.hasNext()
- 返回值:有,
true
;无,false
。
- 返回值:有,
迭代器的遍历
语法格式
元素为自定义对象的遍历
- 定义
Cat
类
- 遍历元素为
Cat
类型的迭代器,需要 向下转型
List
- list有角标
- 根据角标添加元素:index必须<=size,否则会报错
- 根据角标获取元素
并发修改异常
-
并发修改异常:在迭代集合的过程中,是不允许直接修改集合结构。
- 因为,在获取迭代器的时候,迭代器和集合进行了关联,为保持双方数据一致,
modCount
和expectedModCount
需要是相等的。
- 因为,在获取迭代器的时候,迭代器和集合进行了关联,为保持双方数据一致,
-
如需删除,可使用迭代器的删除
-
modCount != expectedModCount
:就会抛出ConcurrentModificationException
,目的是保证 迭代器 与 集合 的内容一致。- modCount:集合修改次数
- expectedModCount:迭代当中记录集合修改的次数
- 迭代器的
remove()
会强制modCount = expectedModCount;
代码示例
- Iterator有
remove
,但无add
。
ListIterator(list迭代器)
- list特有的迭代器
- 拥有
add()
方法
ListIterator的常用方法
hasPrevious()
:迭代器当前元素 之前是否还有元素(倒序)previousIndex()
:倒序游标previous()
:前一个元素
ArrayList数据结构分析
ArrayList为什么可以增加元素
- 数组被初始化就不会被改变
- ArrayList:创建一个容量(角标)增加50%的新数组,把原数据复制到新数组中,然后扔掉原数组。
ArrayList特点
- 查询和修改元素较快:通过索引,就能找到对应的值
- 添加和删除比较慢:需要依次移动元素,即依次更改下标
代码练习:集合去重
元素为字符串
contains()
:判断集合是否包含某个对象,基于Object.equals()
,即地址值的比较。
元素为自定义对象
- 因为
contains()
是地址的比较,需要重写Student类
的equals()
,使其基于name
进行比较。 - 可以使用eclipse的sources -> generate equals 自动生成。
LinkedList
链表
- 优点:链表插入与删除元素,较快
- 缺点:查询与修改比较慢,因为需要遍历
- 与数组(ArrayList)正好相反
链表的结构
链表的插入、删除节点
LinkedList常用方法
listIterator()
:可以使用List父类
的所有方法
独有方法
list.addFirst("myxq");
:在最前添加元素list.addLast("last");
:在最后添加元素list.removeFirst();
:移除第一个元素list.removeLast();
:移除最后一个元素list.get(0)
:根据角标获取元素,源码基于for遍历,效率低;而ArrayList
基于角标直接获取,效率更高。
利用LinkedList构造栈
- 栈:先进后出
Vector
- Vector类很少使用,常用ArrayList
- 从1.2开始并入List接口
Vector特有方法
addElement()
:添加元素,现在使用add()
elements()
:获取所有元素,用于遍历
Vector与ArrayList
- 都是用数组实现
- Vector的synchronized方法都会加同步锁,更安全;而ArrayList无同步锁。