Java-高阶-集合框架

目录

集合框架概述

集合框架的组成:

集合框架的主要优点:

集合框架核心接口

Collection接口详解

Iterator

Iterator接口定义

Iterator的基本使用

Iterator的特点

for-each循环+Lambda表达式

传统的for-each循环

使用Lambda表达式遍历(Java 8+)

使用forEach()方法

带索引的遍历

List接口及其实现类

List接口的特点

主要实现类

ArrayList

ArrayList的底层

关于remove()方法

LinkedList

常用操作

ArrayList和LinkedList的选用

Set接口及其实现类

HashSet

散列码和hashCode()方法

向HashSet中添加元素

TreeSet

TreeSe中对象的比较方法

向TreeSet注入比较器

HashSet和TreeSet的选用

Map及其实现类

Map接口的特点

HashMap

HashMap的迭代方法

Collection集合工具类

多线程封装


集合框架概述

Java集合框架(Java Collections Framework, JCF)是Java语言中用于存储和操作数据集合的一组接口、实现类和算法。它提供了一套标准化的方式来组织和处理数据,是Java编程中最常用的API之一。

集合框架的组成:

  • 接口(Interfaces): 定义集合的抽象行为

  • 实现类(Implementations): 接口的具体实现

  • 算法(Algorithms): 对集合进行操作的方法,如排序、搜索等

集合框架的主要优点:

  • 减少编程工作量

  • 提高程序性能

  • 促进API的互操作性

  • 降低学习成本

  • 提高软件复用性

集合框架核心接口

Java集合框架的核心接口主要位于java.util包中,主要包括:

  1. Collection接口 - 集合层次结构的根接口

  2. List接口 - 有序集合(序列),允许重复元素

  3. Set接口 - 不包含重复元素的集合

  4. Queue接口 - 队列,通常按FIFO(先进先出)排序元素

  5. Deque接口 - 双端队列

  6. Map接口 - 键值对集合,不是Collection的子接口

Collection接口详解

Collection接口是集合层次结构的根接口,定义了所有集合共有的基本操作:

public interface Collection<E> extends Iterable<E> {
    // 基本操作
    int size();
    boolean isEmpty();
    boolean contains(Object element);
    boolean add(E element);         // 可选操作
    boolean remove(Object element); // 可选操作
    Iterator<E> iterator();
    
    // 批量操作
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c); // 可选操作
    boolean removeAll(Collection<?> c);       // 可选操作
    boolean retainAll(Collection<?> c);       // 可选操作
    void clear();                             // 可选操作
    
    // 数组操作
    Object[] toArray();
    <T> T[] toArray(T[] a);
    
    // Java 8新增的默认方法
    default boolean removeIf(Predicate<? super E> filter) { ... }
    default Spliterator<E> spliterator() { ... }
    default Stream<E> stream() { ... }
    default Stream<E> parallelStream() { ... }
}

Iterator

它为各种集合提供了一个统一的遍历方式,实现了"迭代器设计模式。

Iterator接口定义

public interface Iterator<E> {
    // 判断集合中是否还有更多元素
    boolean hasNext();
    返回下一个元素,并且将迭代器指向下一个元素
    // 
    E next();
    
    // 从集合中移除next()返回的最后一个元素(可选操作)
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    
    // Java 8新增:对剩余元素执行操作
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

Iterator的基本使用

  • 基本遍历
List<String> list = Arrays.asList("Java", "Python", "C++");
Iterator<String> iterator = list.iterator();

while (iterator.hasNext()) {
    String language = iterator.next();
    System.out.println(language);
}
  • 使用forEachRemaining(Java 8+)
Iterator<String> iterator = list.iterator();
iterator.forEachRemaining(System.out::println);
  • 移除元素
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Iterator<Integer> iterator = numbers.iterator();

while (iterator.hasNext()) {
    Integer num = iterator.next();
    if (num % 2 == 0) {
        iterator.remove(); // 安全地移除元素
    }
}
// numbers现在是[1, 3, 5]

Iterator的特点

  1. 单向遍历:只能向前遍历,不能后退

  2. 一次性使用:迭代器一旦遍历结束,就不能再使用,需要重新获取

  3. 快速失败(Fail-Fast):如果在迭代过程中集合被修改(除了通过迭代器自身的remove方法),会抛出ConcurrentModificationException

  4. 统一访问方式:为不同集合提供统一的遍历接口

for-each循环+Lambda表达式

在Java中,for-each循环和Lambda表达式是两种强大的遍历集合的方式,它们可以使代码更加简洁和易读。

传统的for-each循环

List<String> list = Arrays.asList("Apple", "Banana", "Orange");

// 传统for-each循环
for (String fruit : list) {
    System.out.println(fruit);
}

使用Lambda表达式遍历(Java 8+)

Java 8引入了Lambda表达式和函数式编程特性,提供了更简洁的遍历方式:

使用forEach()方法

List<String> list = Arrays.asList("Apple", "Banana", "Orange");

// 使用Lambda表达式
list.forEach(fruit -> System.out.println(fruit));

// 使用方法引用(更简洁的形式)
list.forEach(System.out::println);

带索引的遍历

List<String> list = Arrays.asList("Apple", "Banana", "Orange");

IntStream.range(0, list.size())
    .forEach(i -> System.out.println("Index: " + i + ", Value: " + list.get(i)));

List接口及其实现类

  • void add(int index, Object element):在指定位置index上插入元素element。
  • boolean addAll(int index, Collection c):指定位置index上插入集合c中的所有元素,如果List对象发生变化返回true。
  • Object get(int index):返回指定位置index上的元素。 Object remove(int index):删除指定位置index上的元素。
  • Object set(int index, Object element):用元素element取代位置index上的元素,并且返回旧元素的取值。
  • public int indexOf(Object obj):从列表的头部开始向后搜索元素obj,返回第一个出现元素obj的位置,否则返回-1。
  • public int lastIndexOf(Object obj) :从列表的尾部开始向前搜索元素obj,返回第一个出现元素obj的位置,否则返回-1。

List接口的特点

  • 有序集合(序列)

  • 允许重复元素

  • 允许null元素

  • 可以通过索引访问元素

主要实现类

ArrayList

ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。

ArrayList 继承了 AbstractList ,并实现了 List 接口。

  • 基于动态数组实现

  • 随机访问快(O(1))

  • 插入和删除相对慢(O(n))

  • 非线程安全

ArrayList 类位于 java.util 包中,使用前需要引入它,语法格式如下:

import java.util.ArrayList; // 引入 ArrayList 类

ArrayList<E> objectName =new ArrayList<>();  // 初始化

ArrayList的底层

ArrayList中的常用方法包括:

  • ArrayList():从Java SE 8 开始,ArrayList()初始化时得到一个空数组,在第一次 add()运算时将数组扩容为10。
  • ArrayList(int initialCapacity):创建ArrayList 对象,使用参数initialCapacity设置Object[]数组的长度。
  • ensureCapacity():如果要向ArrayList中添加大量元素,可使用此方法对Object[]数组进行指定的扩容。

关于remove()方法

Collection接口中的remove()方法 boolean remove(Object obj) boolean removeAll(Collection c)。 List中声明了一个按位置索引删除的remove()方法 Object remove(int index)。

LinkedList

  • LinkedList 继承了 AbstractSequentialList 类。
  • LinkedList 实现了 Queue 接口,可作为队列使用。
  • LinkedList 实现了 List 接口,可进行列表的相关操作。
  • LinkedList 实现了 Deque 接口,可作为队列使用。
  • LinkedList 实现了 Cloneable 接口,可实现克隆。
  • LinkedList 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。

LinkedList 类位于 java.util 包中,使用前需要引入它,语法格式如下:

// 引入 LinkedList 类
import java.util.LinkedList; 

LinkedList<E> list = new LinkedList<E>();   // 普通创建方法
或者
LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表

常用操作

  • 在列表开头添加元素
LinkedList<String> sites = new LinkedList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
// 使用 addFirst() 在头部添加元素
sites.addFirst("Wiki");
  • 在列表结尾田间元素
// 使用 addLast() 在尾部添加元素
sites.addLast("Wiki");
  • 在列表开头移除元素
sites.removeFirst();
  • 在列表结尾移除元素
sites.removeLast();

ArrayList和LinkedList的选用

  • 如果经常要存取List集合中的元素,那么使用ArrayList采用随机访问的形式(get(index),set(index ,Object element))性能更好。
  • 如果要经常执行插入、删除操作,或者改变List集合的大小,则应该使用LinkedList。

Set接口及其实现类

  • Set接口继承自Collection 接口,它没有引入新方法,所以Set就是一个Collection,只是行为方式不同
  • Set不允许集合中存在重复项,如果试图将两个相同的元素加入同一个集合,则添加无效,add()方法返回false。

PS:Set的实现类依赖添加对象的equals()方法检查对象的唯一性:

  • 只要两个对象使用equals()方法比较的结果为true,Set就会拒绝后一个对象的加入(哪怕它们实际上是不同的对象);
  • 只要两个对象使用equals()方法比较的结果为false,Set就会接纳后一个对象(哪怕它们实际上是相同的对象)。

HashSet

  • 基于哈希表实现

  • 使用HashMap存储元素

  • 插入、删除、查找都是O(1)时间复杂度

  • 不保证迭代顺序

散列码和hashCode()方法

  • 散列码是以某种方法从对象的属性字段产生的整数,Object类中hashCode()方法完成此任务。
  • 要将对象存储在基于散列结构的HashSet,自定义类必须按规则重写Object中的hashCode()方法
  • 所谓的规则就是要保证hashCode()方法与重写的equals()方法完全兼容,即如果a.equals(b)为true,那么a和b也必须通过hashCode()方法得到相同的散列码。
  • 同时,还要保证计算散列码是快速的。

向HashSet中添加元素

底层逻辑:

  • 依据自定义类的hashCode()方法计算得到对象obj的散列码,它是一个整数。(需要自定义类重写hashCode()方法)
  • 将散列码对表长求余,得到对象在散列表中的存储位置p
  • 如果p位置不发生冲突,则将对象obj插入在p位置的链表中
  • 如果p位置发生冲突,在p位置对应的链表中利用equals()方法查找是否已存在obj对象。(需要自定义类重写equals()方法,规则要与hashCode()方法互相匹配)
  1. 如果某个equals()比较的结果为true,说明obj对象已存在,将其舍弃。
  2. 如果与链表中所有对象的equals()比较的结果均为false,说明obj对象尚未存在,obj插入该链表。

TreeSet

TreeSe中对象的比较方法

  • 有一部分类已实现了java.lang.Comparable接口,如基本类型的包装类、String类等,它们在compareTo()方法中定义好了比较对象的规则。像这样的对象可以直接插入TreeSet集合
  • 使用TreeSet存储自定义类对象时,对象所在类要实现Comparable接口,在compareTo()方法中定义对象比较的规则

向TreeSet注入比较器

// 自定义比较器
Comparator<String> lengthComparator = new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }
};

// 创建TreeSet时注入比较器
TreeSet<String> treeSet = new TreeSet<>(lengthComparator);

HashSet和TreeSet的选用

  • 原则:取决于集合中存放的对象,如果不需要对对象进行排序,那么就没有理由在排序上花费不必要的开销,使用HashSet即可。
  • 散列的规则通常更容易定义,只需要打散排列各个对象就行。而TreeSet要求任何两个对象都必须具有可比性,可是在有的应用中比较的规则会很难定义。

Map及其实现类

Map用于保存具有映射关系的数据,它们以键值对<key,value>的形式存在,key与value之间存在一对一的关系

Map接口的特点

  • 键(key)唯一,值(value)可重复

  • 每个键最多只能映射到一个值

  • 不保证元素的顺序(具体取决于实现类)

  • 不是Collection的子接口

键的集合用Set存储,不允许重复、无序;值的集合用List存储,与Set对应、可以重复、有序。

事实上,Java是先实现了Map,然后通过包装一个所有value都为null的Map实现了Set,在底层只有Map。

HashMap

  • 基于哈希表实现(数组+链表+红黑树,JDK8+)

  • 允许null键和null值

  • 非线程安全

  • 不保证元素的顺序

  • 默认初始容量16,负载因子0.75

HashMap的迭代方法

  •  使用EntrySet迭代/键值对(最常用)
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 10);
map.put("Banana", 20);
map.put("Orange", 30);

// 使用EntrySet迭代
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String key = entry.getKey();
    Integer value = entry.getValue();
    System.out.println("Key: " + key + ", Value: " + value);
}

PS:

Object getKey():返回Entry对象的key值。

Object getValue():返回Entry对象的value值。

setValue(Object value):设置Entry对象的value值,并将新值返回。 

  • 按键集合迭代
// 先获取所有键,再通过键获取值
for (String key : map.keySet()) {
    Integer value = map.get(key);
    System.out.println("Key: " + key + ", Value: " + value);
}
  • 使用values()迭代值
for (Integer value : map.values()) {
    System.out.println("Value: " + value);
}

Collection集合工具类

java.util.Collections是Java提供的操作List、Set、Map等集合的工具类:

  • 所有的方法都是静态方法
  • 对集合类功能进行补充
  • 对集合进行再包装,将线程不安全的集合包装为线程安全的集合

多线程封装

在集合框架中,ArrayList、HashSet、TreeSet、HashMap等都是线程不安全的,Collections类提供了多个synchronizedXxx()方法,将指定集合包装为线程同步安全的集合,从而使集合可以工作在并发访问的环境中。

List<String> list = 
     Collections.synchronizedList(new ArrayList<String>());

Map<String,String> map = 
     Collections.synchronizedMap(new HashMap<String,String>());

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值