J03 Java基础 03:集合框架 
集合框架  
 
Java 集合框架(Java Collections Framework, JCF) 是 Java
提供的一套标准化 API,用于处理集合(Collection)类的数据结构。
Java 集合框架包含以下几个核心部分:
接口(Interfaces):定义了集合的基本行为规范,即上图黄色部分。 
实现类(Implementations):为接口提供具体实现,即上图蓝色和紫色部分。 
工具类(Utility
Classes):提供对集合的操作支持,如排序、查找等。 
 
在使用时,接口是不能直接实现的,需要使用具体的类实现。
collection接口 
 
collection接口是所有集合类的跟接口,可以使用集合类的6种方式实现。
例如学生成绩储存的例子:
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public  class  StudentScoreManager  {    public  static  void  main (String[] args)  {                  Collection<Double> scores = new  ArrayList <>();                  **scores.add(85.5 );**         scores.add(90.0 );         scores.add(78.5 );         scores.add(88.0 );                  System.out.println("所有学生成绩:"  + scores);                  double  targetScore  =  90.0 ;         if  (**scores.contains(targetScore)**) {             System.out.println("成绩 "  + targetScore + " 存在于集合中。" );         } else  {             System.out.println("成绩 "  + targetScore + " 不存在于集合中。" );         }                  **scores.remove(78.5 );**         System.out.println("移除78.5后的成绩:"  + scores);                  double  total  =  0.0 ;         for  (**double  score : scores**) {             total += score;         }         double  average  =  total / **scores.size()**;         System.out.println("总成绩:"  + total + ",平均成绩:"  + average);                  if  (**scores.isEmpty()**) {             System.out.println("集合为空。" );         } else  {             System.out.println("集合中有 "  + scores.size() + " 个成绩。" );         }                  **scores.clear()**;         System.out.println("清空后,集合:"  + scores);     } } --- 所有学生成绩:[85.5 , 90.0 , 78.5 , 88.0 ] 成绩 90.0  存在于集合中。 移除78.5 后的成绩:[85.5 , 90.0 , 88.0 ] 总成绩:263.5 ,平均成绩:87.83333333333333  集合中有 3  个成绩。 清空后,集合:[] 
 
上面提供的例子中包括了Collection最为常用的几个api:
add ,contrains ,remove
,size ,isEmpty ,clear 
值得注意的是,在collection中, add
,contrains ,remove
都仅支持单一的参数Object o 
 
以及用于比较两个集合元素是否相等的
equals
 
Collection同时还有迭代器Iterator接口,用于遍历集合中的元素。
Iterator 接口提供以下核心方法:
hasNext()
检查是否还有元素可供迭代。 
返回值:true 表示有下一个元素,false
表示没有。 
  
next()
返回迭代的下一个元素。 
如果没有元素,则抛出 NoSuchElementException。 
  
remove()
删除最近一次通过 next() 方法返回的元素。 
注意:此方法是可选操作,并且只能在调用 next()
之后调用一次。 
  
 
1 2 3 4 5 6 7 8 9 Iterator<Double> iterator = scores.iterator(); while  (iterator.hasNext()) {    double  score  =  iterator.next();     if  (score < 80 ) {         System.out.println("移除低于 80 的成绩:"  + score);         iterator.remove();     } } 
 
List接口 
 
List是继承自 Collection
接口的子接口,表示一个有序的元素集合,List
是专门为需要按照插入顺序存储和访问元素的场景设计的。按照插入顺序进行存储,允许元素重复,可以通过索引快速访问元素。List
的大小是动态的,不需要像数组那样提前定义长度。
 
对于list接口的api,可以从collection的不便之处的角度出发——不支持索引。
因此List接口的主要重写了collection用来增减集合元素的add
,remove 几个函数,同时增加了set ,
get,indexOf这些用于控制元素组成的方法。在list版本中,这些方法接受的参数分别为:
add(int index,E e) 
set(int index,E e) 
get(int index) 
remove(int index) 
indexOf(E e) 
 
 
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public class  ListOperationsDemo  {     public static void main(String[] args) {         // **初始化List **         List <String> names = new ArrayList<>();         names.add("tomori" );         names.add("soyo" );         names.add("sakiko" );         names.add("mutsumi" );         names.add("taki" );                  System.out.println("初始列表: "  + names);         // **依次移除元素**         names.remove(2 ); // 移除 "sakiko"          System.out.println("移除 'sakiko': "  + names);         names.remove(2 ); // 移除 "mutsumi"          System.out.println("移除 'mutsumi': "  + names);         names.remove(2 ); // 移除 "taki"          System.out.println("移除 'taki': "  + names);         names.remove(1 ); // 移除 "soyo"          System.out.println("移除 'soyo': "  + names);         // **添加新元素**         names.add("anon" ); // 加入 "anon"          System.out.println("加入 'anon': "  + names);         names.add("soyo" ); // 再次加入 "soyo"          System.out.println("加入 'soyo': "  + names);         names.add("taki" ); // 再次加入 "taki"          System.out.println("加入 'taki': "  + names);         // **设置特定位置的元素**         names.set (names.indexOf("taki" ), "rikki" ); // 将 "taki"  设置为 "rikki"          System.out.println("将 'taki' 设置为 'rikki': "  + names);         names.add("laana" ); // 加入 "laana"          System.out.println("加入 'laana': "  + names);         names.set (names.indexOf("tomori" ), "tomorin" ); // 将 "tomori"  设置为 "tomorin"          System.out.println("将 'tomori' 设置为 'tomorin': "  + names);         names.set (names.indexOf("soyo" ), "soyorin" ); // 将 "soyo"  设置为 "soyorin"          System.out.println("将 'soyo' 设置为 'soyorin': "  + names);         // **最终列表**         System.out.println("最终列表: "  + names);     } } 
 
 
 
底层实现  
双向链表 
动态数组 
动态数组 
 
线程安全  
否 
否 
是 
 
随机访问效率  
低(O(n)) 
高(O(1)) 
高(O(1)) 
 
插入删除效率  
高(O(1)) 
低(O(n)) 
低(O(n)) 
 
扩容方式  
不适用 
容量增加 1.5 倍 
容量翻倍 
 
使用场景  
频繁插入和删除 
随机访问频繁 
线程安全的场景 
 
 
Set 接口 
 
Set接口是一个不允许重复元素的集合,不能包含两个相等的元素。元素的唯一性是基于equals()方法的定义。
根据不同的实现方式,Set可能会保留插入顺序,完全无序,或者按照某种方式排序。因此没有索引,不能通过索引访问。其操作与Collection很像:
boolean add(E e):向集合中添加元素,如果元素已存在,返回false。 
boolean remove(Object o):移除指定的元素,成功返回true。 
boolean contains(Object o):检查集合是否包含某个元素。 
void clear():清空集合中的所有元素。 
int size():返回集合中元素的数量。 
boolean isEmpty():检查集合是否为空。 
 
 
如上所述,Set接口的主要实现方式之间有一定的区别。
HashSet 
基于哈希表实现,使用HashMap作为底层数据结构。 
不保证元素的顺序。 
插入、删除、查找操作的时间复杂度为O(1)(在哈希函数表现良好的情况下)。 
 
LinkedHashSet 
基于哈希表和链表实现,底层使用LinkedHashMap。LinkedHashMap
是 HashMap
的一个子类,它在存储键值对的同时,通过维护一个双向链表来记录元素的插入顺序。 
保留元素的插入顺序。 
时间复杂度略高于HashSet,但仍为O(1)。 
 
TreeSet 
基于红黑树实现,底层使用NavigableMap(通常是TreeMap)。 
保证元素的自然顺序(或通过提供的Comparator定义的顺序)。 
插入、删除、查找操作的时间复杂度为O(log n)。 
 
Map接口 
 
Map
接口是集合框架中用于存储键值对(key-value)的数据结构,很像python中的字典。
与Set 相似,HashMap 不保证元素顺序,而
LinkedHashMap 保留插入顺序,TreeMap
保证键的自然顺序或自定义顺序。
 
由于Map和Collection并不存在继承关系,他们的方法相差较大。大致上包括以下方法。
put(K key, V value):如果键已存在,返回旧值;否则返回
null。 
get(Object key):如果键不存在,返回
null。 
remove(Object key):如果键存在,返回旧值;否则返回
null。 
containsKey(Object key) 
containsValue(Object value) 
size() 
isEmpty() 
clear() 
keySet():返回所有键的集合(Set)。 
values():返回所有值的集合(Collection)。 
entrySet():返回所有键值对的集合(Set<Map.Entry<K, V>>) 
 
 
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import  java.util.HashMap;import  java.util.Map;import  java.util.Set ;import  java.util.Collection;public class  MyGOBandDemo  {     public static void main(String[] args) {         // 创建一个 HashMap 实例         Map<String, String> mygoBand = new HashMap<>();         // 使用 put 方法添加键值对         mygoBand.put("主唱" , "高松灯" );         mygoBand.put("吉他手" , "千早爱音" );         mygoBand.put("主音吉他手" , "要乐奈" );         mygoBand.put("贝斯手" , "长崎爽世" );         mygoBand.put("鼓手" , "椎名立希" );         // 使用 get 方法获取键对应的值         String vocalist = mygoBand.get("主唱" );         System.out.println("主唱是: "  + vocalist);         // 使用 containsKey 方法检查 Map 中是否包含某个键         boolean hasDrummer = mygoBand.containsKey("鼓手" );         System.out.println("乐队中是否有鼓手? "  + hasDrummer);         // 使用 containsValue 方法检查 Map 中是否包含某个值         boolean hasMember = mygoBand.containsValue("千早爱音" );         System.out.println("乐队中是否有名为千早爱音的成员? "  + hasMember);         // 使用 size 方法获取 Map 中的键值对数量         int  bandSize = mygoBand.size();         System.out.println("乐队成员数量: "  + bandSize);         // 使用 isEmpty 方法检查 Map 是否为空         boolean isBandEmpty = mygoBand.isEmpty();         System.out.println("乐队成员列表是否为空? "  + isBandEmpty);         // 使用 keySet 方法获取所有键的集合         Set <String> roles = mygoBand.keySet();         System.out.println("乐队中的角色: "  + roles);         // 使用 values 方法获取所有值的集合         Collection<String> members = mygoBand.values();         System.out.println("乐队成员的名字: "  + members);         // 使用 entrySet 方法获取所有键值对的集合         Set <Map.Entry<String, String>> entries = mygoBand.entrySet();         System.out.println("乐队成员列表:" );         for  (Map.Entry<String, String> entry : entries) {             System.out.println(entry.getKey() + ": "  + entry.getValue());         }         // 使用 remove 方法删除指定键的键值对         String removedMember = mygoBand.remove("贝斯手" );         System.out.println("被移除的成员: "  + removedMember);         // 使用 clear 方法清空 Map 中的所有键值对         mygoBand.clear();         System.out.println("清空后的乐队成员列表: "  + mygoBand);     } } 
 
Iterator迭代器和ListIterator迭代器 
 
在collection部分简单提及了迭代器的使用。对于这些迭代器来说,它们的主要方法包括hasNext(),next(),remove()。因此,迭代器提供了一个遍历和修改集合中元素的方法。
但需要注意的是,在使用迭代器的同时不能使用如add
这些方法修改集合。
 
如果希望同时使用迭代器和修改元素,或者希望使用双向遍历等功能,可以使用ListIterator。这是专门为List设计的迭代器。
 
单向遍历 
✅ 
✅ 
 
双向遍历 
❌ 
✅ (hasPrevious(),previous()) 
 
移除元素 
✅(remove()) 
✅(remove()) 
 
添加元素 
❌ 
✅(add(E e)) 
 
修改元素 
❌ 
✅(set(E e)) 
 
索引支持 
❌ 
✅(nextIndex(),previousIndex()) 
 
 
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 package collections; import  java.util.ArrayList;import  java.util.Iterator;import  java.util.List ;import  java.util.ListIterator;public class  ListIteratorDemo  {     public static void main(String[] args) {         // **初始化列表**         List <String> list  = new ArrayList<>();         list .add("A" );         list .add("B" );         list .add("C" );         list .add("D" );         System.out.println("初始列表: "  + list );         // **演示Iterator不能同时迭代和add操作**         demonstrateIteratorLimitations(list );         // **演示ListIterator解决方案**         demonstrateListIteratorSolution(list );     }     private static void demonstrateIteratorLimitations(List <String> list ) {         System.out.println("\n使用Iterator尝试迭代和添加元素:" );         try  {             Iterator<String> iterator = list .iterator();             while  (iterator.hasNext()) {                 String element = iterator.next ();                 System.out.println("当前元素: "  + element);                 if  (element.equals("B" )) {                     list .add("E" ); // 尝试在迭代过程中添加元素                 }             }         } catch (Exception e) {             System.out.println("发生异常: "  + e.getClass().getSimpleName() + " - "  + e.getMessage());         }         System.out.println("Iterator操作后的列表: "  + list );     }     private static void demonstrateListIteratorSolution(List <String> list ) {         System.out.println("\n使用ListIterator同时迭代和添加元素:" );         ListIterator<String> listIterator = list .listIterator();         while  (listIterator.hasNext()) {             String element = listIterator.next ();             System.out.println("当前元素: "  + element);             if  (element.equals("B" )) {                 listIterator.add("E" ); // 使用ListIterator添加元素                 System.out.println("添加元素 'E' 到列表" );             }         }         System.out.println("ListIterator操作后的列表: "  + list );     } } --- 初始列表: [A, B, C, D] 使用Iterator尝试迭代和添加元素: 当前元素: A 当前元素: B 发生异常: ConcurrentModificationException - null Iterator操作后的列表: [A, B, C, D, E] 使用ListIterator同时迭代和添加元素: 当前元素: A 当前元素: B 添加元素 'E'  到列表 当前元素: C 当前元素: D 当前元素: E ListIterator操作后的列表: [A, B, E, C, D, E] 
 
 
Iterator适用于简单的只读遍历,而ListIterator适用于需要在遍历过程中动态修改列表内容的场景。
实现类 
 
参考 
 
https://blog.csdn.net/grd_java/article/details/122403602
https://zh.wikipedia.org/zh-cn/Java%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6
https://www.runoob.com/java/java-collections.html