Java集合框架

Java集合框架

集合有时又称容方法,简单地说就是个对象,能将具有相同性质的多个元素汇聚成一个整体。

集合框架(Collections Framework)是用来表现和操纵集合的一个统一的体系结构。

Collection接口

Collection接口时Java集合框架的最顶层接口,它位于java.util包中,是Set接口和List接口(后面会讲)的父接口。

转换构造法

Collection接口实现都有一个带有集合参数的构造方法。也就是说,在这里可以通过”转换”集合的类型来实现存储。

1
Collection<String> a = new ArrayList<>();

a可以是一个List、Set或另外一中Collection。通常,习惯地创建一个新的ArrayList,初始化为包含a中的所有元素。

1
2
List<String> list = new ArrayList<String>(a);
Set<String> set = new HashSet<String>(a);

通过“转换构造法”,list或set对象就包含了集合a中的所有元素。

Collection接口的定义

基本操作:

  • boolean add(E e): 将指定的元素添加到集合中(如果集合允许添加)。
  • boolean remove(Object o): 从集合中移除指定的元素。
  • boolean contains(Object o): 检查集合是否包含指定的元素。
  • int size(): 返回集合中的元素数量。
  • boolean isEmpty(): 检查集合是否为空。
  • Iterator<E> iterator(): 返回一个迭代器,用于遍历集合中的元素。

以及批量操作:

  • boolean addAll(Collection<? extends E> c): 批量添加
  • boolean removeAll(Collection<?> c): 从集合中批量移除元素。
  • boolean containsAll(Collection<?> c): 检查当前集合是否包含所有传入集合的元素
  • bollean retainAll(Collection<?> c): 删除当前集合中所有不在指定集合 c 中的元素
  • void clear(): 移除集合中的所有元素。

数组操作:

  • Object[] toArray(): 将集合转换为数组,数组类型为object
  • <T> T[] toArry(T[] a): 将集合中的元素转换为指定类型的数组,并将其存储在提供的数组中。如果提供的数组足够大,则元素将被存储在这个数组中;否则,将创建一个新的数组。

Collection接口的基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dog d1 = new dog("andy",5);
dog d2 = new dog("tom",2);
Collection<dog> collection = new ArrayList<>();
collection.add(d1);
collection.add(d2);

for(dog o : collection){ //for-each遍历
System.out.println(o.getName());
}

Iterator<String> iterator = collection.iterator(); //迭代遍历
while (iterator.hasNext()) {
System.out.println(iterator.next());
}

collection.remove(d1); //删除d1对象

collection.clear(); //清空

这里我创建了一个dog对象,并给它name和age。

要注意的是,iterator迭代方法同样有遍历的功能,但是Iterator.remove是修改集合唯一安全的方法。如果要移除当前元素。for-each结构隐藏迭代方法,因此不能调用remove方法。同样在多重集合上进行并行迭代也要用迭代器迭代。

下面演示如何过滤Collection集合:

1
2
3
4
5
static void filter(Collection<?> c){
for(Iterator<?> it = c.iterator();it.hasNext();){
if(?cond(it.next())) it.remove();
}
}

Collection接口的批量操作

下面展示表现批量操作强大功能的一个示例,从一个名为c的Collection中移除一个指定元素e的所有实例:

1
c.removeAll(Collections.singleton(e));

或者也可以移除所有null元素:

1
c.removeAll(Collections.singleton(null));

Collections.singleton是一个静态工厂方法,返回一个只包含指定元素的不可变Set集合(没有重复元素)。

在例子中Collections.singleton(e)方法只包含元素e的Set集合,然后就可以用removeAll删除。

Collection数组操作

toArray()方法主要作为集合和老的期望输入数组的API之间的桥梁。

1
2
3
4
5
6
7
8
9
10
11
// 创建并初始化一个 List
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");

// 使用 toArray() 方法将集合转换为 Object 数组
Object[] array = list.toArray();

// 使用 toArray(T[] a) 方法将集合转换为指定类型的数组
String[] array = list.toArray(new String[0]);

Set接口

Set是一个不能包含重复元素的接口,是Collection接口的子接口,并且只包含从Collection继承过来的方法,并增加了对add()方法的使用限制,不允许有重复的元素。Set()还修改了equals()和hashCode()方法的实现,允许对Set实例进行内容上的比较,即使它们实现类型不同。如果两个Set实例包含相同的元素,那么它们就是相等的。

Set定义

主要方法:

  • 继承了Collection接口的所有方法。
  • 没有专门定义新的方法,但子接口和实现类提供了对集合不重复性要求的具体实现。

主要实现类:

  • HashSet: 基于哈希表的实现,不保证元素的顺序,通常提供快速的插入、删除和查找操作。
  • TreeSet: 基于红黑树的实现,按自然顺序或构造时提供的比较器进行排序。
  • LinkedHashSet: 结合了哈希表和链表的特点,保持插入顺序的同时提供较快的操作速度。

Java平台包含3个通用目的的Set实现就是HashSet、TreeSet、LinkedHashSet这三个。

Set接口的基本操作

那么Set和Collection有什么区别呢?下面看这个实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CollectionSetExample {
public static void main(String[] args) {
// 使用 Collection 接口
Collection<String> collection = new ArrayList<>();
collection.add("Apple");
collection.add("Banana");
collection.add("Cherry");
System.out.println("Collection: " + collection);

// 使用 Set 接口
Set<String> set = new HashSet<>(); //这里用了哈希存放
set.add("Apple");
set.add("Banana");
set.add("Apple"); // 重复元素不会被添加
System.out.println("Set: " + set);
}
}

我们可以看到,这其中最大的区别就是Set不能重复添加元素。

Set接口的批量操作

批量操作特别适合于Set接口:

  • s1.containsAll(s2):如果s2是s1的一个子集合,返回true
  • s1.addAll(s2):将s1变换为s1和s2的并集
  • s1.retain(s2):将s1变换为s1和s2的交集
  • s1.removeAll(s2):将s1不对称地变换为s1和s2的差集

addAll示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
Set<String> set1 = new HashSet<>();
set1.add("Apple");
set1.add("Banana");

Set<String> set2 = new HashSet<>();
set2.add("Cherry");
set2.add("Date");

// 将 set2 的所有元素添加到 set1 中
set1.addAll(set2);

System.out.println("Set1 after addAll: " + set1);
//Set1 after addAll: [Apple, Banana, Cherry, Date]

removeAll示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
Set<String> set1 = new HashSet<>();
set1.add("Apple");
set1.add("Banana");
set1.add("Cherry");

Set<String> set2 = new HashSet<>();
set2.add("Banana");
set2.add("Cherry");

// 从 set1 中移除 set2 中的所有元素
set1.removeAll(set2);

System.out.println("Set1 after removeAll: " + set1);

List接口

List是一个有序的集合(又是被称为序列)。List可以包含重复的元素。除了从Collection继承过来的操作之外,List接口还包括以下操作:

  • 按位置访问:根据元素在序列中的位置索引访问元素
  • 查找:在序列中查找指定对象,并返回其位置索引
  • 迭代:扩展了Iteractor接口,以利用序列的顺序特性
  • List子集合:在序列上执行任意范围的操作

List接口的定义

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.Collection;

public interface List<E> extends Collection<E> {
void add(int index, E element);
boolean addAll(int index, Collection<? extends E> c);
E get(int index);
E set(int index, E element);
E remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
List<E> subList(int fromIndex, int toIndex);
}

Java平台常见的List实现包括: ArrayList(基于动态数组)、LinkedList(基于双向链表)和 Vector(线程安全的动态数组)。

List接口的操作

1. 添加元素
  • void add(int index, E element)

    • 在指定位置插入元素。

    示例:

    1
    2
    3
    4
    List<String> list = new ArrayList<>();
    list.add("Apple");
    list.add("Banana");
    list.add(1, "Orange"); // 在位置 1 插入 "Orange"
  • boolean addAll(int index, Collection<? extends E> c)

    • 从指定位置开始,将指定集合中的所有元素添加到当前列表中。

    示例:

    1
    2
    3
    4
    5
    6
    List<String> list = new ArrayList<>();
    list.add("Apple");
    list.add("Banana");

    List<String> newItems = Arrays.asList("Orange", "Grapes");
    list.addAll(1, newItems); // 从位置 1 开始添加 newItems 中的元素
2. 访问元素
  • E get(int index)

    • 获取指定位置的元素。

    示例:

    1
    2
    3
    4
    5
    List<String> list = new ArrayList<>();
    list.add("Apple");
    list.add("Banana");

    String item = list.get(0); // 获取位置 0 的元素
  • E set(int index, E element)

    • 替换指定位置的元素。

    示例:

    1
    2
    3
    4
    5
    List<String> list = new ArrayList<>();
    list.add("Apple");
    list.add("Banana");

    list.set(1, "Orange"); // 将位置 1 的元素替换为 "Orange"
3. 删除元素
  • E remove(int index)

    • 移除指定位置的元素。
    1
    2
    3
    4
    5
    List<String> list = new ArrayList<>();
    list.add("Apple");
    list.add("Banana");

    list.remove(1); // 移除位置 1 的元素
4. 查找元素
  • int indexOf(Object o)

    • 返回指定元素第一次出现的索引,如果不在列表中,则返回 -1。

    示例:

    1
    2
    3
    4
    5
    List<String> list = new ArrayList<>();
    list.add("Apple");
    list.add("Banana");

    int index = list.indexOf("Banana"); // 获取 "Banana" 的位置
  • int lastIndexOf(Object o)

    • 返回指定元素最后一次出现的索引,如果不在列表中,则返回 -1。

    示例:

    1
    2
    3
    4
    5
    6
    List<String> list = new ArrayList<>();
    list.add("Apple");
    list.add("Banana");
    list.add("Banana");

    int index = list.lastIndexOf("Banana"); // 获取 "Banana" 最后出现的位置
5. 子列表
  • List<E> subList(int fromIndex, int toIndex)

    • 返回当前列表中从 fromIndex(包含)到 toIndex(不包含)的部分列表。
    1
    2
    3
    4
    5
    6
    7
    List<String> list = new ArrayList<>();
    list.add("Apple");
    list.add("Banana");
    list.add("Cherry");
    list.add("Date");

    List<String> subList = list.subList(1, 3); // 获取子列表 [Banana, Cherry]
6. 迭代器
  • ListIterator<E> listIterator()

    • 返回一个 ListIterator,从列表的开始处迭代。
  • ListIterator<E> listIterator(int index)

    • 返回一个 ListIterator,从指定的位置开始迭代。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    List<String> list = new ArrayList<>();
    list.add("Apple");
    list.add("Banana");
    list.add("Cherry");

    ListIterator<String> iterator = list.listIterator();
    while (iterator.hasNext()) {
    System.out.println(iterator.next());
    }

    ListIterator<String> iteratorFromIndex = list.listIterator(1);
    while (iteratorFromIndex.hasNext()) {
    System.out.println(iteratorFromIndex.next());
    }

Map接口

Map接口的定义

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
27
28
29
import java.util.Collection;
import java.util.Set;

public interface Map<K, V> {
//基本操作
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(Object key);
V put(K key, V value);
V remove(Object key);
//批量操作
void putAll(Map<? extends K, ? extends V> m);
void clear();
//集合视图
Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();

//嵌套接口
interface Entry<K, V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
}
}

Java平台包括3中通用的Map实现:HashMap、TreeMap和LinkedHashMap。

Map接口的基本操作

1. 基本操作
  • int size()

    • 返回 Map 中键值对的数量。

    示例:

    1
    2
    3
    4
    5
    Map<String, Integer> map = new HashMap<>();
    map.put("One", 1);
    map.put("Two", 2);

    int size = map.size(); // 返回 2
  • boolean isEmpty()

    • 检查 Map 是否为空(即是否没有键值对)。

    示例:

    1
    boolean isEmpty = map.isEmpty();  // 返回 false
2. 键和值的存在性检查
  • boolean containsKey(Object key)

    • 检查 Map 是否包含指定的键。

    示例:

    1
    boolean hasKey = map.containsKey("One");  // 返回 true
  • boolean containsValue(Object value)

    • 检查 Map 是否包含指定的值。

    示例:

    1
    boolean hasValue = map.containsValue(2);  // 返回 true
3. 获取和设置键值对
  • V get(Object key)

    • 根据键获取对应的值。如果键不存在,则返回 null

    示例:

    1
    Integer value = map.get("One");  // 返回 1
  • V put(K key, V value)

    • 将指定的键值对添加到 Map 中。如果键已经存在,则更新对应的值,并返回之前的值。

    示例:

    1
    map.put("Three", 3);  // 将 "Three" 键与 3 值添加到 map 中
  • V remove(Object key)

    • 根据键移除对应的键值对,并返回被移除的值。

    示例:

    1
    Integer removedValue = map.remove("Two");  // 移除 "Two" 键对应的值 2
4. 批量操作
  • void putAll(Map<? extends K, ? extends V> m)

    • 将指定 Map 中的所有键值对添加到当前 Map 中。

    示例:

    1
    2
    3
    4
    5
    Map<String, Integer> anotherMap = new HashMap<>();
    anotherMap.put("Four", 4);
    anotherMap.put("Five", 5);

    map.putAll(anotherMap); // 将 anotherMap 的所有键值对添加到 map 中
  • void clear()

    • 移除 Map 中的所有键值对,使 Map 变为空。

    示例:

    1
    map.clear();  // 清空 map
5. 视图操作
  • Set<K> keySet()

    • 返回 Map 中所有键的集合。

    示例:

    1
    Set<String> keys = map.keySet();  // 获取 map 的所有键
  • Collection<V> values()

    • 返回 Map 中所有值的集合。

    示例:

    1
    Collection<Integer> values = map.values();  // 获取 map 的所有值
  • Set<Map.Entry<K, V>> entrySet()

    • 返回 Map 中所有键值对的集合,每个键值对作为 Map.Entry 对象存在。

    示例:

    1
    2
    3
    4
    Set<Map.Entry<String, Integer>> entries = map.entrySet();
    for (Map.Entry<String, Integer> entry : entries) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
    }
6. 嵌套接口 Entry
  • K getKey()
    • 返回 Map.Entry 对象中的键。
  • V getValue()
    • 返回 Map.Entry 对象中的值。
  • V setValue(V value)
    • 设置 Map.Entry 对象中的值,并返回之前的值。
  • boolean equals(Object o)
    • 判断两个 Map.Entry 对象是否相等。
  • int hashCode()
    • 返回 Map.Entry 对象的哈希码。
示例

比如我们可以做一个数组中单词的显示次数小程序:

1
2
3
4
5
6
7
Map<String,Integer> m = new HashMap<>();
for(String a : args){
Integer freq = m.get(a);
m.put( a, (freq == null) ? 1 : freq+1 ); //(键,值)
}
System.out.println(m.size() + "个不同的单词");
System.out.println(m);

args:

1
java to is is be if if 

output:

1
2
5个不同的单词
{java=1, be=1, is=2, to=1, if=2}

Java集合框架
https://bayeeaa.github.io/2024/08/29/Java集合框架/
Author
Ye
Posted on
August 29, 2024
Licensed under