浅谈 Java 集合框架

简介: Java 最初版本只提供了最初的几个 Java 集合框架个类:• Vector• Stack• Hashable• BitSet• Enumeration其中 Enumeration 接口提供了一种用于访问任意容器中各个元素的抽象机制。Java 集合类库将接口( interface )与实现(implementation)分离。

队列是如何分离的

队列是如何分离的队列涉及的几个操作:

• 在队尾添加元素

• 在队头删除元素

• 查找队列中元素的个数


特点:先入先出队列的接口:

public interface Queue<E> // a simplified form of the interface in the stardard library
{
  void add(E element);
  E remove();
  int size();
}


在数据结构课中,队列通常有两种实现方式:


  1. 使用循环数组;但这种方式的局限是队列的长度有限。
  2. 使用链表代码表示如下:
public class CircularArrayQueue<E> implements Queue<E>  // not an actual library class
{
    private int head;
    private int tail;
    CircularArrayQueue(int capacity) {...}
    public void add(E element) {...}
    public E remove() {...}
    public int size() {...}
    private E[] elements;
}
public class LinkedListQueue<E> implements Queue<E>  // not an actual library class
{
    private Link head;
    private Link tail;
    LinkedListQueue() {...}
    public void add(E element) {...}
    public E remove() {...}
    public int size() {...}
}

注释:实际上,Java 类库没有名为 CirclularArrayQueue 和 LinkedListQueue 的类。这里只是以这些类作为示例来解释集合接口与实现在概念上的区分。


Queue 的使用

假设定义了上述的 CircularArrayQueueLinkedListQueue 之后,就可以直接使用:

Queue<Customer> expressLane = new CircularArrayQueue<>(100);
expressLane.add(new Customer("Harry")
Queue<Customer> expressLane = new LinkedListQueue<>();
expressLane.add(new Customer("Bug")

循环数组要比链表高效,因此多数人优先选择循环数组。

但是循环数组是一个有界数组,即容量有限。如果使用的对象数量没有上限,最好使用链表实现。


Collection 接口


所有通用集合实现都有一个带有 Collection 参数的构造函数,此构造函数初始化新集合以包含指定集合中的所有元素,即它允许转换集合的类型。

如把一个 Collection<String> s,它可以转化成 List、Set 或其他类型的 Collection。如:

List<String> s = new ArrayList<String>(c);


Collection 接口包含执行基本操作的方法:

  • int size()
  • boolean isEmpty()
  • boolean contains(Object element
  • boolean add(E element)
  • boolean remove(Object element)
  • Interator<E> interator()


Collection 接口还包含对整个集合进行操作的方法:

  • boolean containsAll(Collection<?> c)
  • boolean addAll(Collection<? extends E> c)
  • boolean removeAll(Collection<?> c)
  • boolean retainAll(Collection<?> c)
  • void clear()

Collection 接口还存在用于数组操作的附加方法,例如:

  • Object[] toArray()
  • <T> T[] toArray(T[] a)


JDK 8 及更高版本中,Collection 接口还公开方法 Stream<E> stream() 和 Stream<E> parallelStream(),帮助从底层集合中获取顺序或并行流。

public interface Collection<E> {
  boolean add(E element);
  Interator<E> iterator();  // 返回一个用于访问集合中各个元素的迭代器
}


add 方法用于向集合中添加元素。如果成功添加元素改变了集合就返回 true;如果集合没有发生改变就返回 false。比如在集合( set )中添加一个对象,如果这个元素在集合中已经存在,这时 add 方法就没有奏效,因为集合中不允许有重复的对象。


interator 方法用于返回一个实现了 Interator 接口的对象,可以使用这个迭代器对象依次访问集合中的元素。


集合遍历接口--迭代器

Iterator 接口包含 4 个方法:

public interface Interator<E> {
  E next(); // 返回将要访问的下一个对象。如果已经到达了集合的末尾,将抛出一个 NoSuchElement-Exception
  boolean hasNext();  // 如果存在另一个可访问的元素,返回 true
  void remove();  // 删除上次访问的对象。这个方法必须紧跟在访问一个元素之后执行。如果上次访问之后集合已经发生了变化,这个方法将会抛出一个 IllegalStateException
  default void forEachRemaining(Consumer<? super E> action); // 访问元素,并传递到指定的动作,直到再没有更多元素,或者这个动作抛出一个异常
}


通过反复调用 next 方法,可以逐个访问集合中的每个元素。但是,如果到达了集合的末尾,next 方法将抛出一个 NoSuchElementException。因此,在需要调用 next 之前调用 hasNext 方法。

hashNext 如果迭代器对象还有多个可以访问的元素,这个方法就返回 true。

Collection<String> c = ...;
Interator<String> iter = c.iterator();
while (iter.hasNext()) {
  String element = iter.next();
  // do something with element
}


for each 循环可以更加简练地表达同样的循环操作:

for (String element : c) {
  // do something with element
  System.out.Println(element);
}


for each 循环可以处理任何实现了 Iterable 接口的对象,这个对象只包含一个抽象方法:

public interface Iterable<E> {
  Iterator<E> iterator();
}


JDK8 及更高版本中,迭代集合的首选方法是获取流并对其执行聚合操作。聚合操作需要与 Lambda 表达式结合使用,以使用较少的代码使编程更具表现力。

myShapeCollection.stream()
  .filter(e -> e.getColor() == Color.RED)
  .forEach(e -> System.out.Println(e.getName()));


访问元素的顺序取决于集合类型。

  • 如果迭代处理一个 ArrayList,迭代器索引从 0 开始,没迭代一次,索引值加 1 。
  • 如果访问 HashSet 中的元素,会按照一种基本上随机的顺序获得元素。(每一次访问的顺序都是唯一的)


Iterator 接口的 remove 方法将会删除上次调用 next 方法时返回的元素。目的是:删除某个元素前最该先看一下这个元素。


集合接口批量操作

批量操作对整个集合执行操作。包含基本的方法有:

  • contailsAll : 如果目标 Collection 包含指定 Collection 中的所有元素,就返回 true。
  • addAll : 将指定 Collection 中的所有元素添加到目标 Collection。
  • removeAll : 从目标 Collection 中删除包含在指定 Collection 中的所有元素。
  • retainAll : 从目标 Collection 中删除所有所有未包含在指定 Collection 中删除所有未包含在指定 Collection 中的元素。
  • clear : 从集合中删除所有元素。


如,检测任意集合是否包含指定元素的泛型方法:

public static <E> boolean contains(Collection<E> c, Object obj) {
    for (E element : c)
    if (element.equals(obj))
        return true;
    return false;
}


其他方法

还有一些实用方法非常有用,应该将它们提供给用户实用。下面列举一部分:

int size()  // 返回当前存储在集合中的元素个数
boolean isEmpty() // 如何集合中没有元素,返回 true
boolean contains(Object obj)  // 如果集合中包含了一个与obj相等的元素,返回true
boolean equals(Object other)  // 如果集合与 other 集合相等,返回true
boolean add(E element) // 将一个元素添加到集合中。由于这个调用改变了集合,返回 true
boolean addAll(Collection<? extends E> from) // 将 other 集合中的所有元素添加到这个集合。如果由于这个调用改变了这个集合,返回true
boolean remove(Object obj)  // 从这个集合中删除等于 obj 的对象。如果有匹配的对象被删除,返回true
boolean removeAll(Collection<?> c) // 从这个集合中删除obj集合中存在的所有元素。如果这个调用改变了集合,返回true
default boolean removeIf(Predicate<? super E> filter // JDK8, 从这个集合中删除filter返回true的所有元素,如果因为这个调用改变了集合,返回true
void clear() // 从这个集合中删除所有的元素
boolean retainAll(Collection<?> c) // 从这个集合中删除所有与other集合元素不同的元素。如果由于这个调用改变了集合,返回true
Object[] toArray() // 返回这个集合中的对象的数组
<T> T[] toArray(T[] arrayToFill)


<T> T[] toArray(T[] arrayToFill) :返回这个集合中的对象的数组。如果 arrayToFill 足够大,就将集合中的元素填入这个数组中,剩余空间填补 null;否则,分配一个新数组,其成员类型与 arrayToFill 的成员类型相同,其长度等于集合的大小,并填充集合元素。

相关文章
|
22天前
|
安全 Java 容器
【Java集合类面试二十七】、谈谈CopyOnWriteArrayList的原理
CopyOnWriteArrayList是一种线程安全的ArrayList,通过在写操作时复制新数组来保证线程安全,适用于读多写少的场景,但可能因内存占用和无法保证实时性而有性能问题。
|
22天前
|
存储 安全 Java
【Java集合类面试二十五】、有哪些线程安全的List?
线程安全的List包括Vector、Collections.SynchronizedList和CopyOnWriteArrayList,其中CopyOnWriteArrayList通过复制底层数组实现写操作,提供了最优的线程安全性能。
|
22天前
|
Java
【Java集合类面试二十八】、说一说TreeSet和HashSet的区别
HashSet基于哈希表实现,无序且可以有一个null元素;TreeSet基于红黑树实现,支持排序,不允许null元素。
|
22天前
|
Java
【Java集合类面试二十六】、介绍一下ArrayList的数据结构?
ArrayList是基于可动态扩展的数组实现的,支持快速随机访问,但在插入和删除操作时可能需要数组复制而性能较差。
|
12天前
|
Java
用JAVA架建List集合为树形结构的代码方法
这段代码定义了一个表示树形结构的 `Node` 类和一个用于构建树形结构的 `TreeController`。`Node` 类包含基本属性如 `id`、`pid`、`name` 和 `type`,以及子节点列表 `children`。`TreeController` 包含初始化节点列表并将其转换为树形结构的方法。通过过滤和分组操作实现树形结构的构建。详情可见:[代码示例链接1](http://www.zidongmutanji.com/zsjx/43551.html),[代码效果参考链接2](https://www.257342.com/sitemap/post.html)。
25 5
|
10天前
|
Java 数据库连接 Apache
Java进阶-主流框架总结与详解
这些仅仅是 Java 众多框架中的一部分。每个框架都有其特定的用途和优势,了解并熟练运用这些框架,对于每一位 Java 开发者来说都至关重要。同时,选择合适框架的关键在于理解框架的设计哲学、核心功能及其在项目中的应用场景。随着技术的不断进步,这些框架也在不断更新和迭代以适应新的开发者需求。
29 1
|
12天前
|
存储 Java 程序员
Java中的集合框架:从入门到精通
【8月更文挑战第30天】在Java的世界里,集合框架是一块基石,它不仅承载着数据的存储和操作,还体现了面向对象编程的精髓。本篇文章将带你遨游Java集合框架的海洋,从基础概念到高级应用,一步步揭示它的奥秘。你将学会如何选择合适的集合类型,掌握集合的遍历技巧,以及理解集合框架背后的设计哲学。让我们一起探索这个强大工具,解锁数据结构的新视角。
|
13天前
|
存储 算法 Java
Java中的集合框架深度解析云上守护:云计算与网络安全的协同进化
【8月更文挑战第29天】在Java的世界中,集合框架是数据结构的代言人。它不仅让数据存储变得优雅而高效,还为程序员提供了一套丰富的工具箱。本文将带你深入理解集合框架的设计哲学,探索其背后的原理,并分享一些实用的使用技巧。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往高效编程的大门。
|
20天前
|
存储 算法 Java
Java 中的同步集合和并发集合
【8月更文挑战第22天】
20 5
|
22天前
|
存储 Java
【Java集合类面试二十九】、说一说HashSet的底层结构
HashSet的底层结构是基于HashMap实现的,使用一个初始容量为16和负载因子为0.75的HashMap,其中HashSet元素作为HashMap的key,而value是一个静态的PRESENT对象。