JavaBasic-4--集合类
集合类
Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。
集合框架体系
Collection
基本介绍
- Collection实现⼦类可以存放多个元素,每个元素可以是Object
- Collection的实现类,有些可以存放重复的元素,有些不可以
- Collection的实现类,有些是有序的(List),有些不是有序(Set)
- Collection接⼝没有直接的实现⼦类,是通过它的⼦接⼝Set 和 List 来实现的
接口常用方法
方法 | 说明 |
---|---|
add | 添加单个元素 |
remove | 删除指定元素 |
contains | 查找元素是否存在 |
size | 获取元素个数 |
isEmpty | 判空 |
clear | 清空 |
addAll | 添加多个元素 |
containsAll | 查找多个元素 |
removeAll | 删除多个元素 |
迭代器
基本介绍
- lterator对象称为迭代器,主要⽤于遍历 Collection 集合中的元素
- 实现了Collection接⼝的集合都有⼀个iterator()⽅法,⽤以返回⼀个实现了lterator接⼝的对象,即可以 返回⼀个迭代器
- lterator 仅⽤于遍历集合,lterator 本身并不存放对象
- 在调⽤it.next()⽅法之前必须要调⽤it.hasNext()进⾏检测。
- 若不调⽤,且下⼀条记录⽆效,直接调⽤ it.next()会抛出NoSuchElementException异常
常用方法
方法 | 说明 |
---|---|
boolean hasNext() | 用于判断集合中当前位置是否有元素可以被取出 |
E next() | 获取当前位置的元素,并将迭代器对象移向下一个位置 |
void remove() | 删除上一次调用next()方法时返回的元素,每次调用next()方法只能调用一次此方法 |
案例
1 | Collection col = new ArrayList(); |
增强for循环
作用是简化数组和Collection集合的遍历
内部原理依然是Iterator迭代器
实现Iterable接口的类才可以使用增强for循环和Iterator迭代器
注意避免在增强for循环中对数组或集合元素删除或更改
三种循环的使用场景
需要操作索引使用普通for循环
需要遍历过程中删除元素,使用迭代器
仅仅遍历元素使用增强for循环
List
基本介绍
- List集合类中元素有序(即添加顺序和取出顺序⼀致)、且可重复
- List集合中的每个元素都有其对应的顺序索引,即⽀持索引
- List容器中的元素都对应⼀个整数型的序号记载其在容器中的位置,可以根据序号存取容器元素
- ArrayList、LinkedList、Vector
常用方法
方法名 | 说明 |
---|---|
void add(int index,E element) | 在指定位置插入元素 |
E remove(int index) | 删除指定位置的元素并返回 |
E set(int index,E element) | 修改指定位置的元素并返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
List的实现类ArrayList
- 底层数据结构是数组,查询快,增删慢
- 实现自动扩容的机制
- 每次扩容的容量是之前的1.5倍
List的实现类LinkedList
- 底层数据结构是双向链表,查询慢,增删快
LinkedList特有方法:
方法名 | 说明 |
---|---|
public void addFirst() | 在开头插入元素 |
public void addLast() | 在末尾插入元素 |
public E getFirst() | 获取第一个元素 |
public E getLast() | 获取最后一个元素 |
public E removeFirst() | 删除并返回第一个元素 |
public E removeLast() | 删除并返回最后一个元素 |
Set
基本介绍
- ⽆序(添加和取出的顺序不⼀致),没有索引
- 不允许重复元素,所以最多包含⼀个null
遍历方式
- 迭代器
- 增强for
- 不能使⽤索引⽅式获取(普通遍历循环)
HashSet 注意事项
- 可以存放null值,但是只能有⼀个null
- Hashset不保证元素是有序的,取决于hash后,再确定索引的结果
- 不能有重复元素/对象
HashSet 底层机制和源码分析
- HashSet 底层是 HashMap
添加⼀个元素时,先得到hash值会转成索引值
找到存储数据表table,看这个素引位置是否⼰经存放的有元素如果没有,直接加⼊
如果有调⽤equals ⽐较,如果相同,就放弃添加,如果不相同,则添加到最后
- 在Java8中,如果⼀条链表的元素个数超过 TREEIFY THRESHOLD(默认是8),井且table的⼤⼩> =MIN TREEIFY CAPACITY(默认64)就会进⾏树化(红⿊树)
Map
interface Map<K,V>
是双列集合的顶层接口,K表示键的数据类型,V表示值的数据类型键不能重复,值允许重复,键值是对应的,一个键只能对应一个值
(键+值)这个整体称为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”
由于Map是接口,所以创建Map对象可以通过多态的方式
常用方法
方法名 | 说明 |
---|---|
V put(K k,V v) | 添加元素 |
V remove(K k) | 根据键删除键值对元素,并且将被删除的键值对中的值返回 |
void clear() | 清空所有的键值对 |
boolean containsKey(K k) | 判断集合是否包含指定的键 |
boolean containsValue(V v) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 返回集合的长度(键值对个数) |
Set |
获取所有键的集合 |
V get(K k) | 根据键获取值 |
Set |
获取所有键值对对象的集合 |
put()方法注意事项:如果添加的键值对中的键在集合中不存在,则直接添加进去,返回的是null;如果添加的键值对中的键在集合中已经存在,那么会替换掉键值对中原来的值,并且将被替换的值返回
遍历方式
由 keySet() 方法获取所有的键,然后遍历键,在遍历键的同时通过 get() 方法实现键值对的遍历
1 | Set<String> set = map.keySet(); |
由 entrySet() 方法获得键值对对象的集合,Map.EntryK getKey()
和V getValue()
分别可以获取键值对的键和值
1 | Set<Map.Entry<String, String>> entries = map.entrySet(); |
HashMap
- HashMap底层是哈希表
- 存放的方式与HashSet类似,但是需要将键值对封装成Entry对象再进行存放
- 依赖HashCode()方法和equals()方法保证键的唯一,由键的哈希值决定存放位置,由键的equals()方法判断元素是否重复
- 如果键的类型是自定义的类,那么需要重写HashCode()方法和equals()方法
TreeMap
- TreeMap底层是红黑树
- 依赖自然排序或比较器排序,对键进行排序
- 如果键是自定义类型的对象,则该类需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则
可变参数
可变参数是指形参个数可以改变
格式:
修饰符 返回值类型 方法名(数据类型...变量名){}
范例:
1
public void func(int...arr){}
可变参数其实是一个数组
如果方法参数还含有其他参数,可变参数需要放在最后边
创建不可变集合
在List、Set、Map接口中,存在静态方法 of(可变参数) ,可以创建一个不可变集合
这个不可变集合不能添加、删除、修改
可以结合集合的带参构造,实现集合的批量添加
Map接口中还有一个 ofEntries(可变参数) 方法可以提高代码阅读性,作用和Map.of()相同,但是ofEntries()中的可变参数会先封装成一个Entry对象
范例
1
2List<String> list = List.of("a","b","c"); // 利用可变参数创建不可变集合
ArrayList<String> list1 = new ArrayList<>(list); // 利用不可变集合创建集合