集合类

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Collection col = new ArrayList();

col.add(new Book("三国演义", "罗贯中", 10.1));
col.add(new Book("⼩李⻜⼑", "古⻰", 5.1));
col.add(new Book("红楼梦", "曹雪芹", 34.6));

// 1. 先得到 col 对应的 迭代器
Iterator iterator = col.iterator();

// 2. 使⽤while循环遍历
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj=" + obj);
}
// 3. 当退出while循环后 , 这时iterator迭代器,指向最后的元素

// 4. 如果希望再次遍历,需要重置我们的迭代器
iterator = col.iterator();


while(it.hasNext()){
String s = it.next();
if("abc".equals(s)){
it.remove();//将迭代器返回的最后一个元素删除
}
}

增强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 keySet() 获取所有键的集合
V get(K k) 根据键获取值
Set> entrySet() 获取所有键值对对象的集合

put()方法注意事项:如果添加的键值对中的键在集合中不存在,则直接添加进去,返回的是null;如果添加的键值对中的键在集合中已经存在,那么会替换掉键值对中原来的,并且将被替换的值返回

遍历方式

keySet() 方法获取所有的键,然后遍历键,在遍历键的同时通过 get() 方法实现键值对的遍历

1
2
3
4
Set<String> set = map.keySet();
for(String key:set){
map.get(key);
}

entrySet() 方法获得键值对对象的集合,Map.Entry 接口中有两个方法K getKey()V getValue()分别可以获取键值对的键和值

1
2
3
4
5
Set<Map.Entry<String, String>> entries = map.entrySet();
for(Map.Entry<String,String> entry:entries){
String k = entry.getKey();
String v = entry.getValue();
}

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
    2
    List<String> list = List.of("a","b","c"); // 利用可变参数创建不可变集合
    ArrayList<String> list1 = new ArrayList<>(list); // 利用不可变集合创建集合