Java Collection API 中的接口和方法

Java Collection API

概要

Java Collections Framework(Java集合框架)是Java语言中的一组类和接口,提供了在Java中处理对象集合的基础设施。集合是通常作为一个单一单元存储、操作和处理的对象组。Java集合框架通过提供用于处理集合的通用和一致的API来简化集合的处理。

以下是Java集合API中的一些关键组件和概念:

  1. 接口
    • Collection(集合):这是Java集合框架的根接口,它表示一组对象并定义了添加、删除和迭代元素等基本操作。
    • List(列表):有序元素的集合,允许重复。
    • Set(集):不重复元素的无序集合。
    • Map(映射):键值对的集合。
    • ArrayList(数组列表):使用动态数组实现List接口。
    • LinkedList(链表):使用双向链表实现List接口。
    • HashSet(哈希集):使用哈希表存储实现Set接口。
    • TreeSet(树集):使用排序树结构实现Set接口。
    • HashMap(哈希映射):使用哈希表实现Map接口。
    • TreeMap(树映射):使用排序树结构实现Map接口。
  2. 迭代器:该框架提供了迭代器,用于遍历集合中的元素。一些常见的迭代器接口包括Iterator(迭代器)、ListIterator(列表迭代器)和SetIterator(集合迭代器)。
  3. 泛型类型:大多数集合类和接口都是泛型的,这意味着您可以指定它们持有的对象类型。例如,ArrayList<Integer>只能保存整数。
  4. 算法:该框架在Collections类中提供了一组静态方法,用于在集合上执行操作,如排序、搜索、洗牌等。
  5. 比较器Comparator接口允许您为集合中的对象定义自定义排序规则。

List

List 是 Java 集合框架中的一个接口,表示有序元素的集合,允许元素重复。以下是如何使用 List 接口的一些常见操作:

ArrayList

  1. 创建一个 List 对象

    可以使用各种类来实现 List 接口,例如 ArrayListLinkedList。下面是一个使用 ArrayList 的示例:

    List<String> myList = new ArrayList<>();
    
  2. 添加元素

    使用 add 方法可以向列表中添加元素。

    myList.add("苹果");
    myList.add("香蕉");
    myList.add("樱桃");
    
  3. 访问元素

    使用 get 方法可以按索引访问列表中的元素。

    String fruit = myList.get(0); // 获取第一个元素,索引从0开始
    
  4. 修改元素

    通过索引可以修改列表中的元素。

    myList.set(1, "葡萄"); // 将索引为1的元素修改为"葡萄"
    
  5. 删除元素

    使用 remove 方法可以删除列表中的元素。

    myList.remove(2); // 删除索引为2的元素("樱桃")
    
  6. 查找元素

    可以使用 contains 方法检查列表中是否包含特定元素。

    boolean containsBanana = myList.contains("香蕉");
    
  7. 获取列表大小

    使用 size 方法可以获取列表中元素的数量。

    int size = myList.size();
    
  8. 迭代列表

    使用循环或迭代器可以遍历列表中的元素。

    for (String fruit : myList) {
        System.out.println(fruit);
    }
    

    或者使用迭代器:

    Iterator<String> iterator = myList.iterator();
    while (iterator.hasNext()) {
        String fruit = iterator.next();
        System.out.println(fruit);
    }
    
  9. 排序列表

    使用 Collections.sort() 方法可以对列表进行排序。

    Collections.sort(myList); // 对列表进行升序排序
    

LinkedList

LinkedList 是 Java 集合框架中的一个实现了 List 接口的类,它基于双向链表数据结构。以下是如何使用 LinkedList 的一些常见操作:

  1. 创建一个 LinkedList 对象

    可以使用 LinkedList 类来创建一个新的链表:

    LinkedList<String> linkedList = new LinkedList<>();
    
  2. 添加元素

    使用 add 方法可以向链表尾部添加元素:

    linkedList.add("苹果");
    linkedList.add("香蕉");
    linkedList.add("樱桃");
    

    还可以使用 addFirstaddLast 方法在链表的开头和结尾添加元素:

    linkedList.addFirst("葡萄");
    linkedList.addLast("桃子");
    
  3. 访问元素

    使用 get 方法可以按索引访问链表中的元素:

    String fruit = linkedList.get(0); // 获取第一个元素,索引从0开始
    
  4. 修改元素

    通过索引可以修改链表中的元素:

    linkedList.set(1, "柚子"); // 将索引为1的元素修改为"柚子"
    
  5. 删除元素

    使用 remove 方法可以删除链表中的元素。可以按索引删除,也可以按元素内容删除:

    linkedList.remove(2); // 删除索引为2的元素("樱桃")
    linkedList.remove("桃子"); // 删除元素内容为"桃子"的元素
    
  6. 获取链表大小

    使用 size 方法可以获取链表中元素的数量:

    int size = linkedList.size();
    
  7. 迭代链表

    使用循环或迭代器可以遍历链表中的元素,也可以使用 getFirstgetLast 方法获取链表的第一个和最后一个元素:

    for (String fruit : linkedList) {
        System.out.println(fruit);
    }
    
    String firstFruit = linkedList.getFirst();
    String lastFruit = linkedList.getLast();
    
  8. 在链表头部和尾部操作元素

    LinkedList 提供了 addFirstaddLastgetFirstgetLast 等方法,以便在链表的头部和尾部执行操作。

    linkedList.addFirst("草莓");
    linkedList.addLast("橙子");
    String firstFruit = linkedList.getFirst();
    String lastFruit = linkedList.getLast();
    

​ 这些是一些常见的 LinkedList 操作。由于 LinkedList 是基于链表的,因此它在插入和删除操作方面可以比 ArrayList 更高效,但在随机访问方面性能可能较差。您可以根据具体需求选择合适的实现类。

二者比较

ArrayListLinkedList 都是 Java 集合框架中的列表(List)实现,用于存储有序的元素。它们有不同的内部数据结构和性能特点,适用于不同的使用场景。

ArrayList

  1. 内部数据结构ArrayList 基于动态数组实现。它使用数组来存储元素,可以根据需要自动增长或收缩数组的大小。
  2. 特点
    • 随机访问快:由于使用数组,ArrayList 支持常数时间内的随机访问(通过索引访问元素)。
    • 插入和删除较慢:在中间插入或删除元素时,需要移动其他元素,因此性能较差。
  3. 适用场景
    • 当需要快速随机访问元素,而不需要频繁的插入和删除操作时,ArrayList 是一个不错的选择。

LinkedList

  1. 内部数据结构LinkedList 基于双向链表实现。每个元素都包含对前一个和后一个元素的引用。
  2. 特点
    • 随机访问较慢:由于需要从头或尾遍历链表来查找元素,随机访问的性能较差。
    • 插入和删除快:在中间插入或删除元素时,只需更新相邻元素的引用,因此性能较好。
  3. 适用场景
    • 当需要频繁插入和删除元素,而不需要频繁随机访问时,LinkedList 是一个更合适的选择。
    • 另外,LinkedList 适合在双向遍历(向前和向后)时使用。

总结

  • 如果您的应用程序需要快速随机访问元素,并且插入和删除操作相对较少,ArrayList 可能是更好的选择,因为它具有更好的随机访问性能。
  • 如果您的应用程序需要频繁进行插入和删除操作,尤其是在中间插入和删除元素时,LinkedList 可能更适合,因为它具有更好的插入和删除性能。
  • 您还可以根据具体需求和性能要求选择合适的数据结构。有时候,混合使用这两种数据结构也是一种有效的策略。

Iterator

​ 迭代器(Iterator)是 Java 集合框架中的一个重要概念,它是用于遍历(迭代)集合中的元素的一种设计模式。迭代器提供了一种标准的方式来访问集合的元素,而不需要了解集合的内部结构。迭代器常用于循环遍历集合,无论集合的具体实现是数组、链表还是其他数据结构。

​ 在 Java 中,几乎所有的集合类(如 List、Set、Map)都实现了迭代器。以下是迭代器的常见用法和方法:

  1. 获取迭代器

    • 使用 iterator() 方法获取集合的迭代器。
    • 对于 List 类型的集合,还可以使用 listIterator() 方法获取一个列表迭代器,它允许双向遍历并在遍历过程中修改元素。
    List<String> myList = new ArrayList<>();
    Iterator<String> iterator = myList.iterator();
    
  2. 遍历集合

    • 使用 hasNext() 方法检查是否还有下一个元素。
    • 使用 next() 方法获取下一个元素。
    while (iterator.hasNext()) {
        String element = iterator.next();
        // 处理 element
    }
    
  3. 删除元素

    • 使用迭代器的 remove() 方法可以安全地删除集合中的元素,而不会引发并发修改异常。
    iterator.remove(); // 删除当前元素
    
  4. ListIterator(列表迭代器)

    • 对于 List 类型的集合,可以使用 listIterator() 方法获取列表迭代器,它允许双向遍历,并可以在遍历过程中修改元素。
    • ListIterator 提供了额外的方法,如 previous()set(),用于在遍历中访问前一个元素和修改当前元素。
    ListIterator<String> listIterator = myList.listIterator();
    while (listIterator.hasNext()) {
        String element = listIterator.next();
        // 处理 element
    }
    

迭代器是一种非常有用的工具,因为它提供了一种一致的方式来遍历各种不同类型的集合,而不必关心它们的内部实现。迭代器也能够在遍历过程中安全地进行元素删除操作,这对于修改集合而不破坏遍历的情况非常有帮助。

Set

​ 在Java中,Set 是一个接口,表示一种集合,其中不允许重复的元素。Set 集合通常用于存储一组唯一的元素。Java提供了多个实现 Set 接口的类,包括 HashSetLinkedHashSetTreeSet。下面是如何使用 Set 集合的基本操作:

  1. 创建一个 Set 对象

    您可以使用不同的实现类来创建 Set 集合,例如 HashSetLinkedHashSetTreeSet

    javaCopy code
    Set<String> mySet = new HashSet<>(); // 创建一个 HashSet
    
  2. 添加元素

    使用 add 方法将元素添加到集合中。请注意,集合不会允许重复的元素。

    mySet.add("苹果");
    mySet.add("香蕉");
    mySet.add("樱桃");
    
  3. 检查元素是否存在

    使用 contains 方法来检查集合中是否包含特定元素。

    boolean containsBanana = mySet.contains("香蕉");
    
  4. 删除元素

    使用 remove 方法从集合中删除元素。

    mySet.remove("樱桃");
    
  5. 获取集合大小

    使用 size 方法获取集合中的元素数量。

    int size = mySet.size();
    
  6. 遍历集合

    您可以使用迭代器(Iterator)来遍历 Set 集合中的元素。

    Iterator<String> iterator = mySet.iterator();
    while (iterator.hasNext()) {
        String element = iterator.next();
        System.out.println(element);
    }
    
  7. 清空集合

    使用 clear 方法可以清空集合中的所有元素。

    mySet.clear();
    
  8. 不允许重复元素

    Set 集合不允许重复的元素。如果尝试添加一个已经存在的元素,它将被忽略。

    mySet.add("苹果");
    mySet.add("苹果"); // 这个操作不会添加重复的 "苹果"
    

Set 集合非常适合用于存储一组唯一的元素,以及在元素存在性检查方面具有高效性能。根据具体需求,您可以选择不同的 Set 实现,例如 HashSet 提供了快速查找,LinkedHashSet 保持元素的插入顺序,而 TreeSet 则保持元素的有序性。

三种集合的对比

HashSet, LinkedHashSet, 和 TreeSet 都是 Java 集合框架中的 Set 接口的实现,用于存储一组唯一的元素。它们之间的区别主要在于内部数据结构和性能特点:

  1. HashSet:

    • 内部数据结构:HashSet 基于哈希表实现,使用哈希函数来存储和检索元素。
    • 无序性:HashSet 不保证元素的顺序,元素的存储顺序是不确定的。
    • 查找性能:HashSet 具有快速的查找性能,平均情况下,查找操作的时间复杂度为 O(1)。
    • 不允许重复元素:HashSet 不允许重复的元素。
    Set<String> hashSet = new HashSet<>();
    
  2. LinkedHashSet:

    • 内部数据结构:LinkedHashSet 基于哈希表和链表实现,保持元素的插入顺序。
    • 有序性:LinkedHashSet 保持元素的插入顺序,因此迭代时元素的顺序与插入顺序相同。
    • 查找性能:与 HashSet 相似,具有快速的查找性能。
    • 不允许重复元素:LinkedHashSet 不允许重复的元素。
    Set<String> linkedHashSet = new LinkedHashSet<>();
    
  3. TreeSet:

    • 内部数据结构:TreeSet 基于红黑树(一种自平衡二叉搜索树)实现,保持元素的有序性。
    • 有序性:TreeSet 保持元素的有序性,元素会按照它们的自然顺序或自定义比较器的顺序进行排序。
    • 查找性能:相对于哈希表实现,TreeSet 的查找性能略慢,平均情况下,查找操作的时间复杂度为 O(log n)。
    • 不允许重复元素:TreeSet 不允许重复的元素。
    Set<String> treeSet = new TreeSet<>();
    

选择哪种实现取决于需求:

  • 如果需要一个无序的集合,主要关注元素的查找性能,HashSet 可能是最佳选择。
  • 如果需要一个有序的集合,但仍希望具有快速查找性能,LinkedHashSet 可能是更合适的,因为它保持了元素的插入顺序。
  • 如果需要一个有序的集合,并且对元素的顺序有严格的要求,TreeSet 是一个好选择,因为它可以按照自然顺序或自定义比较器的顺序进行排序。

无论选择哪个实现,Set 接口确保您将只存储唯一的元素。

Map

Map 是 Java 集合框架中的一个接口,用于存储键值对(key-value pairs)。每个键映射到一个值,因此 Map 允许您通过键来查找和检索值。Map 接口的常见实现包括 HashMapLinkedHashMapTreeMapHashTable 等。以下是关于如何使用 Map 的基本操作:

  1. 创建一个 Map 对象

    您可以使用不同的实现类来创建 Map 集合,例如 HashMapLinkedHashMapTreeMap

    Map<String, Integer> myMap = new HashMap<>();
    
  2. 添加键值对

    使用 put 方法将键值对添加到 Map 中。

    myMap.put("苹果", 10);
    myMap.put("香蕉", 5);
    myMap.put("樱桃", 20);
    
  3. 获取值

    使用 get 方法通过键获取值。

    int appleCount = myMap.get("苹果");
    
  4. 检查键是否存在

    使用 containsKey 方法来检查键是否存在于 Map 中。

    boolean containsBanana = myMap.containsKey("香蕉");
    
  5. 删除键值对

    使用 remove 方法从 Map 中删除键值对。

    myMap.remove("樱桃");
    
  6. 获取键集合和值集合

    使用 keySet() 方法可以获取所有键的集合,使用 values() 方法可以获取所有值的集合。

    Set<String> keys = myMap.keySet();
    Collection<Integer> values = myMap.values();
    
  7. 遍历 Map

    使用迭代器或增强型 for 循环遍历 Map 中的键值对。

    for (Map.Entry<String, Integer> entry : myMap.entrySet()) {
        String key = entry.getKey();
        int value = entry.getValue();
        System.out.println(key + ": " + value);
    }
    
  8. 清空 Map

    使用 clear 方法可以清空 Map 中的所有键值对。

    myMap.clear();
    

Map 是一种非常有用的数据结构,它将值与唯一的键相关联,以便快速检索和更新数据。不同的 Map 实现有不同的性能特点和用途,根据需求,可以选择适当的实现。

HashMap、LinkedHashMap、TreeMap和HashTable的区别

HashMap, LinkedHashMap, TreeMap, 和 Hashtable 都是 Java 中的 Map 接口的实现,用于存储键值对。它们有不同的性能特点和用途,以下是它们的主要区别:

  1. HashMap:

    • 内部数据结构:HashMap 基于哈希表实现,使用哈希函数将键映射到值。
    • 无序性:HashMap 不保证键值对的顺序,元素的存储顺序是不确定的。
    • 查找性能:HashMap 具有快速的查找性能,平均情况下,查找操作的时间复杂度为 O(1)。
    • 允许空键和值:HashMap 允许存储空键和空值。
    Map<String, Integer> hashMap = new HashMap<>();
    
  2. LinkedHashMap:

    • 内部数据结构:LinkedHashMap 基于哈希表和双向链表实现,保持键值对的插入顺序。
    • 有序性:LinkedHashMap 保持键值对的插入顺序,因此迭代时键值对的顺序与插入顺序相同。
    • 查找性能:与 HashMap 相似,具有快速的查找性能。
    • 允许空键和值:LinkedHashMap 允许存储空键和空值。
    Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
    
  3. TreeMap:

    • 内部数据结构:TreeMap 基于红黑树(一种自平衡二叉搜索树)实现,保持键值对的有序性。
    • 有序性:TreeMap 保持键值对的有序性,元素会按照它们的自然顺序或自定义比较器的顺序进行排序
    • 查找性能:相对于哈希表实现,TreeMap 的查找性能略慢,平均情况下,查找操作的时间复杂度为 O(log n)。
    • 不允许空键:TreeMap 不允许存储空键,但允许存储空值。
    Map<String, Integer> treeMap = new TreeMap<>();
    
  4. Hashtable:

    • 内部数据结构:Hashtable 也基于哈希表实现,类似于 HashMap
    • 无序性:Hashtable 不保证键值对的顺序,元素的存储顺序是不确定的。
    • 查找性能:与 HashMap 相似,具有快速的查找性能。
    • 不允许空键和值:Hashtable 不允许存储空键或空值。
    • 线程安全Hashtable 是线程安全的,多个线程可以同时访问它。
    Map<String, Integer> hashtable = new Hashtable<>();
    

选择哪种实现取决于需求

  • 如果需要一个无序的键值对集合,主要关注查找性能,HashMap 是一个常用的选择。
  • 如果需要一个有序的键值对集合,并关心插入顺序,LinkedHashMap 可能是更合适的。
  • 如果需要一个有序的键值对集合,同时需要按照特定顺序排序TreeMap 可以满足您的需求。
  • 如果需要一个线程安全的键值对集合,Hashtable 可能是一个选择,尽管在现代 Java 中,更多的人使用 ConcurrentHashMap 来获得更好的性能。

无论您选择哪种实现,Map 接口提供了一种方便的方式来存储和检索键值对,可以根据具体的需求进行选择。

Comparator

Comparator 是 Java 中的一个接口,用于定义自定义比较规则,以便对对象进行排序。Comparator 接口通常与集合类(如 ListTreeSetTreeMap 等)一起使用,以实现自定义排序。

Comparator 接口定义了一个用于比较两个对象的方法 compare,该方法需要实现者提供比较规则。这个方法返回一个整数,表示两个对象的相对顺序。通常,返回值为负数表示第一个对象小于第二个对象,返回值为正数表示第一个对象大于第二个对象,返回值为零表示两个对象相等。

以下是 Comparator 接口的基本用法:

  1. 实现 Comparator 接口

    创建一个实现了 Comparator 接口的类,并实现 compare 方法以定义比较规则。比如,以下是一个用于对字符串按照长度进行排序的比较器:

    public class StringLengthComparator implements Comparator<String> {
        @Override
        public int compare(String s1, String s2) {
            return Integer.compare(s1.length(), s2.length());
        }
    }
    
  2. 使用 Comparator 进行排序

    将实现了 Comparator 接口的比较器对象传递给集合类的排序方法。

    List<String> strings = new ArrayList<>();
    strings.add("apple");
    strings.add("banana");
    strings.add("cherry");
    
    Collections.sort(strings, new StringLengthComparator());
    
    // 现在 strings 中的字符串按照长度排序
    
  3. 使用 lambda 表达式

    在 Java 8 及更高版本中,您可以使用 lambda 表达式来简化 Comparator 的创建。例如,上述的比较器可以用 lambda 表达式编写如下:

    Comparator<String> lengthComparator = (s1, s2) -> Integer.compare(s1.length(), s2.length());
    Collections.sort(strings, lengthComparator);
    
  4. 逆序排序

    如果需要逆序排序,您可以使用 Collections.reverseOrder()Comparator.reverseOrder() 来创建逆序比较器。

    Comparator<String> reverseLengthComparator = Collections.reverseOrder(new StringLengthComparator());
    // 或者
    Comparator<String> reverseLengthComparator = Comparator.reverseOrder();
    

Comparator 接口使您能够灵活定义排序规则,因此您可以对集合中的对象进行多样化的排序。这对于自定义排序需求非常有用,如按不同属性、多条件排序等。

算法

​ Java Collections Framework提供了java.util.Collections类,其中包含了各种用于操作集合的静态算法。这些算法可用于排序、查找、洗牌等各种集合操作。以下是一些常见的Collections类中的算法:

  1. 排序(Sorting):
    • sort(List<T> list):对列表进行自然顺序排序。
    • sort(List<T> list, Comparator<? super T> c):使用自定义比较器对列表进行排序。
    • reverse(List<?> list):反转列表中的元素的顺序。
  2. 查找(Searching):
    • binarySearch(List<? extends Comparable<? super T>> list, T key):在已排序的列表中使用二分查找来查找元素。
    • binarySearch(List<? extends T> list, T key, Comparator<? super T> c):在已排序的列表中使用自定义比较器进行二分查找。
  3. 洗牌(Shuffling):
    • shuffle(List<?> list):随机重新排列列表中的元素。
    • shuffle(List<?> list, Random rnd):使用指定的随机数生成器进行洗牌。
  4. 复制(Copying):
    • copy(List<? super T> dest, List<? extends T> src):将一个列表的内容复制到另一个列表。
  5. 填充(Filling):
    • fill(List<? super T> list, T obj):使用指定的元素填充列表。
  6. 最大值和最小值(Max and Min):
    • max(Collection<? extends T> coll):返回集合中的最大元素。
    • max(Collection<? extends T> coll, Comparator<? super T> comp):使用自定义比较器返回最大元素。
    • min(Collection<? extends T> coll):返回集合中的最小元素。
    • min(Collection<? extends T> coll, Comparator<? super T> comp):使用自定义比较器返回最小元素。
  7. 不可修改的集合(Immutable Collections):
    • unmodifiableCollection(Collection<? extends T> c):将集合包装成不可修改的集合,防止修改操作。
  8. 同步集合(Synchronized Collections):
    • synchronizedCollection(Collection<T> c):将集合包装成同步集合,使其线程安全。

这些是一些常见的Collections类中的算法。这些算法可用于对不同类型的集合进行操作,如ListSetMap。它们提供了一种便捷的方式来执行常见的集合操作,无需手动实现算法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值