为什么要使用集合
存储多个数据可以使用数组,但由于数组在内存中是连续存储的,所以会有一些限制。比如数组在创建时就要指定长度,即可以容纳的元素个数,且指定后无法更改;数组在创建时需要指定元素的类型,并且所有元素都必须是该类型或其子类;添加或删除数组中的元素需要创建一个新数组再进行元素复制,比较麻烦。下面是 Person 数组扩容的示意代码。
(资料图)
// 给 people1 数组末尾添加一个元素public class PersonArray { public static void main(String[] args) { Person[] people1 = new Person[1]; people1[0] = new Person(); // 创建新数组 Person[] people2 = new Person[people1.length + 1]; // 复制 people1 数组的元素到 people2 for (int i = 0; i < people1.length; i++) { people2[i] = people1[i]; } // 添加新元素 people2[people2.length - 1] = new Person(); }}
数组可以通过索引快速访问和操作元素,在许多场景下仍然是非常有用的,但如果需要动态调整大小或保存不同类型的元素,则可以考虑使用集合类来代替数组。集合类还提供了一系列增加、删除、修改和查找元素的方法。集合框架中还提供了多种优化和封装好的实现类,通过使用合适的集合类可以更高效地组织和操作数据。
集合框架体系
Java 的集合类很多,主要有Collection
和Map
两个接口,层次关系如下图。
Collection
接口有List
和Set
这两个重要的子接口,它们的实现子类都是单列集合。其中List
接口表示有序的、可以包含重复元素的集合,常见的实现类有ArrayList
、LinkedList
和Vector
。Set
接口表示无序的且不包含重复元素的集合,常见的实现类有HashSet
、TreeSet
和LinkedHashSet
。
Map
接口实现子类是双列集合,表示一组键值对的映射,其中每个键都是唯一的。常见的实现类有HashMap
、Hashtable
和Properties
。
public class AddElements() { public static void main(String[] args) { ArrayList
Collection 接口和常用方法
Collection 接口实现类的特点
Collection
实现类(通常通过其中一个子接口间接实现Collection)可以存放多个 Object 类型的元素。有些Collection
接口的实现类可以存放重复的元素,有些则不可以。有些Collection
接口的实现类是有序的(List
),有些是无序的(Set
)。Collection
接口没有直接实现类,提供了更具体的子接口(如Set
和List
)的实现。
所有通用的Collection实现类都会提供两个"标准"构造方法:一个无参构造方法,来创建一个空的集合,以及一个带有单个Collection类型参数的构造方法,创建一个与参数集合具有相同元素的新集合。实际上,后一种构造方法可以复制任何集合,生成一个与参数集合元素相同的所需类型的集合。
public class CollectionMethod() { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add(1); list.add(2); list.add(3); System.out.println(list);// [1, 2, 3] Vector
Collection 接口常用方法
下面的代码以其间接实现类ArrayList
演示Collection
接口的常用方法。
public class CollectionMethod() { public static void main(String[] args) { Collection collection = new ArrayList<>(); // boolean add(E e) // 给集合中添加指定的元素,添加成功则返回 true。 // 如果此集合不允许重复元素并且已经包含了指定的元素,则返回 false。 // 支持此操作的实现类可能会对添加到该集合中的元素进行限制。 // 如果一个集合拒绝添加某个特定元素的原因不是因为集合已经包含该元素, // 会抛出一个异常(而不是返回 false)。 collection.add("hello"); collection.add(10); collection.add(true); // 下面一条语句执行后输出:collection = [hello, 10, true] System.out.println("collection = " + collection); // boolean remove(Object o) // 从集合中移除指定元素的一个实例。如果集合包含多个满足 // (o==null ? e==null : o.equals(e))条件的元素 e, // 则移除第一个元素 e。移除完成后返回 true。 collection.remove("hello"); // 下面一条语句执行后输出:collection = [10, true]System.out.println("collection = " + collection); // boolean contains(Object o) // 如果此集合包含指定元素,则返回 true。更准确地说,当且仅当此集合包含至少 // 一个满足(o==null ? e==null : o.equals(e))条件的元素 e 时,返回 true。 System.out.println(collection.contains(10));// true // int size() // 返回此集合中的元素数量。 System.out.println(collection.size());// 2 // boolean isEmpty() // 判断集合是否为空。 System.out.println(collection.isEmpty());// false // void clear() // 清空集合中的元素。 collection.clear(); // 下面一条语句执行后输出:collection = [] System.out.println("collection = " + collection); // boolean addAll(Collection extends E> c) // 将指定集合中的所有元素添加到此集合中。 Collection collection1 = new ArrayList(); collection1.add("Mary"); collection1.add("Luck"); collection.addAll(collection1); // 下面一条语句执行后输出:collection = [Mary, Luck] System.out.println("collection = " + collection); // boolean containsAll(Collection> c) // 判断此集合是否包含指定集合中的所有元素 System.out.println(collection.containsAll(collection1));// true // boolean removeAll(Collection> c) // 从此集合中移除与指定集合中相同的所有元素。 // 在此调用返回后,此集合将不包含与指定集合共有的任何元素。 collection.add("King"); collection.removeAll(collection1); // 下面一条语句执行后输出:collection = [King] System.out.println("collection = " + collection); }}
Collection 接口如何遍历元素
使用 Iterator(迭代器)
Iterator
接口是集合的迭代器,主要用于遍历Collection
集合中的元素。所有实现了Collection
接口的实现类,都有一个iterator()
方法,用以返回一个实现了Iterator
接口的对象,即可以返回一个迭代器。
Iterator
接口的方法:
// 判断是否还有下一个元素boolean hasNext() // 返回集合中的下一个元素E next()// 从底层集合中移除此迭代器返回的最后一个元素。每次调用 next() 只能调用此方法一次。// 如果在调用此方法之前尚未调用过 next() 方法,或者在最后一次调用 next() 方法之后// 已经调用了过一次 remove() 方法,则抛出 IllegalStateException 异常。default void remove() // 对剩余的每个元素执行给定的操作,直到所有元素被处理完或操作抛出异常为止。default void forEachRemaining(Consumer super E> action)
迭代器的使用示例代码:
public class CollectionIterateor() { public static void main(String[] args) { Collection col = new ArrayList(); col.add("红楼梦"); col.add("西游记"); col.add("三国演义"); col.add("水浒传"); // 遍历 col 集合 // 先获得 col 对应的迭代器 Iterator iterator = col.iterator(); // 使用 while 循环遍历 while (iterator.hasNext()) {// 判断是否还有元素 Object obj = iterator.next(); // 返回下一个元素,类型是 Object System.out.println("obj = " + obj); } // 当退出 while 循环后,iterator 迭代器指向最后一个元素 // 此时再调用 next() 会抛出 NoSuchElementException 异常 // iterator.next(); // 如果需要再次遍历,需要重制迭代器 System.out.println("===第二次遍历==="); iterator = col.iterator(); while (iterator.hasNext()) { Object obj = iterator.next(); System.out.println("obj = " + obj); } }}
由于当迭代器中不存在下一个元素时,直接调用 iterator.next() 方法会抛出 NoSuchElementException 异常,所以调用 iterator.next() 方法之前需要调用 iterator.hasNext() 方法。
增强 for 循环
增强 for 循环是简化版的 iterator,本质一样,只能用来遍历集合或数组。基本语法如下:
for(元素类型 元素名 : 集合名或数组名){访问元素;}
public class EnhancedFor() { public static void main(String[] args) { Collection collection = new ArrayList(); collection.add("mary"); collection.add(true); collection.add(10); for (Object o : collection) { System.out.println("o = " + o); } }}