5

Java 核心技术学习笔记:集合接口

 1 year ago
source link: https://blog.51cto.com/yuzhou1su/5445410
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Java 核心技术学习笔记:集合接口

原创

宇宙之一粟 2022-07-05 23:26:41 博主文章分类:Java 开发成长之路 ©著作权

文章标签 迭代器 java 链表 文章分类 Java 编程语言 私藏项目实操分享 阅读数162

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 的使用

假设定义了上述的 ​​CircularArrayQueue​​​ 和 ​​LinkedListQueue​​ 之后,就可以直接使用:

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 的成员类型相同,其长度等于集合的大小,并填充集合元素。

Reference: Java 核心技术 卷 1 :基础知识(原书第11版)

  • 收藏
  • 评论
  • 分享
  • 举报

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK