Java常用集合类总结

时间:2021-04-05 17:00:47

Java常用集合类总结

作者:麦田里的码农
目录:


1.集合类(Collection)的由来

  Java是面向对象的语言,该语言对事物的描述是通过定义对象体现的。在编程时,常常需要存储多个相同类型的对象实例,所以就需要一个容器类型的变量。目前所学过的知识里面,学过的容器类型仅有:数组、StringBuilder和StringBuffer。但是,StringBuilder和StringBuffer的结果是一个字符串,不一定满足我们的要求,所以我们只能选择数组,这就是对象数组。

  对象数组又不能适应变化的需求,因为数组的长度是固定的,这个时候,为了适应变化的需求,Java就提供了集合类。集合类也被称为容器类,所有的集合类都位于java.util包下。”集合”一词最初是一个数学概念,java提供的集合类和数学中的集合有相似之处,但又有区别。

2.集合和数组的区别

既然java集合弥补了数组的不足之处,那么集合和数组有什么区别呢?区别有三点:

  • A:长度区别。数组的长度固定;集合长度可变,内部实现了自动扩容。
  • B:内容不同。数组存储的是同一种类型的元素,而集合可以存储不同类型的元素。
  • C:元素的数据类型问题。数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用类型

3.如何着手学习集合(类)

  集合类虽用于存储多个对象,但是不同的应用场景下,对存储对象的方式也有不同需求。比如说,要求存储的这多个对象中不能有相同的;再比如,要求这多个对象在存储时按照某种规则排序等等。针对不同的需求,Java就提供了不同的集合类,最常用的集合类有ArrayList、LinkedList、HashSet、HashMap等等。Java提供的这些集合类底层实现采用不同的数据结构,但这些个集合类是有共性的,我们把这些集合类的共性内容不断的向上提取,最终就能形成集合的继承体系结构,如下图所示。
Java常用集合类总结

  由上图可知,集合类主要由两个接口派生:Collection和Map;Collection和Map接口位于集合类继承体系的顶层,是根接口,它们分别有子接口。Collection派生出Set、List、Queue三个接口,其中Set代表无序不可重复的集合,List代表有序可以重复的集合,Queue是Java1.5以后提供的队列集合实现。而Map则代表了具有映射关系的集合
  Java没有提供根接口的直接实现,而是提供了子接口的实现。在学习集合类时,建议从根接口学起,根接口是共性的东西、里面的功能了解后,学习子接口和对应的实现会比较快。
  值得注意的是,JDK1.5之前,集合类仅仅是一个容器,可以把不同类型的对象保存在容器中,从而丢失 了所有对象的数据类型,把所有对象当成Object类型处理。JDK1.5之后增加了泛型,集合才记住了容器中对象的数据类型。建议直接学习JDK1.5及更高版本的集合类。

4.Collection 接口

Collection 作为集合的一个根接口,JDK7中定义了 15 个方法:

package java.util;

public interface Collection<E> extends Iterable<E> {
//1.长度功能
int size(); //获取元素个数
//2:添加功能
boolean add(E e); //添加一个元素,成功时返回 true
boolean addAll(Collection<? extends E> c);//添加一个集合的元素,集合改变则返回true
//3:删除功能
void clear(); //移除所有元素
boolean remove(Object o); //移除一个元素,成功时返回 true
boolean removeAll(Collection<?> c);//移除一个集合的元素
//4:判断功能
boolean isEmpty(); //集合是否为空
boolean contains(Object o); //判断集合中是否包含指定的元素
boolean containsAll(Collection<?> c);//判断集合中是否包含指定的集合元素
//5:获取迭代器(遍历),继承自Iterable接口,返回集合的Iterator对象
Iterator<E> iterator();
//6:交集功能
boolean retainAll(Collection<?> c);
//7:把集合转换为数组
Object[] toArray();
<T> T[] toArray(T[] a);

boolean equals(Object o);
int hashCode();
}

下面写了两个测试类,印证Collection中的几个功能。

4.1 测试一:Collection基本功能

import java.util.*;
public class TestCollection {

public static void main(String[] args) {
Collection c= new ArrayList();

//添加元素。集合中不能存放基本类型的值,但java支持自动封箱。
c.add("baidu");
c.add("baidu");
c.add(6);
c.add("test");
c.add("解忧杂货店");
//集合大小
System.out.println("c集合的大小为:"+c.size());
//是否包含
System.out.println("c集合中是否包含baidu字符串:"+c.contains("baidu"));

//将输出[ele1,ele2,...]的形式,说明Collection重写了toString()
System.out.println("c集合中的元素有:"+c);

//删除元素
c.remove(6);
System.out.println("c集合中的元素有:"+c);

Collection col =new HashSet();
col.add("解忧杂货店");
col.add("baidu");

//containAll()
System.out.println("c集合是否包含col集合?"+c.containsAll(col));
//removeAll(),c集合中有相同值时,也一同去掉了,如“baidu”
c.removeAll(col);
System.out.println("c集合的元素:"+c);
}
}

输出的结果为:
c集合的大小为:5
c集合中是否包含baidu字符串:true
c集合中的元素有:[baidu, baidu, 6, test, 解忧杂货店]
c集合中的元素有:[baidu, baidu, test, 解忧杂货店]
c集合是否包含col集合?true
c集合的元素:[test]

  上面创建了两个Collection对象,其中c集合是ArrayList,col集合是HashSet,虽然他们的实现类不同,但把他们都当做Collection来使用时,使用Collection的15大成员函数是没有区别的。

4.2 测试二:Collection遍历

import java.util.*;

public class TraverseCollection {

public static void main(String[] args) {
Collection c = new ArrayList();

// 添加元素。集合中不能存放基本类型的值,但java支持自动封箱。
c.add("阿里");
c.add("baidu");
c.add("解忧杂货店");

// 遍历Collection
Iterator it = c.iterator();
while (it.hasNext()) {
// it.next();返回的数据类型是Object类型,需强制类型转换
String tmp = (String) it.next();
System.out.print(tmp + " ");
if ("baidu".equals(tmp)) {
// 从集合中删除上一次next方法返回的元素
it.remove();
}
//对tmp赋值,不会改变集合元素本身
tmp = "腾讯";
}

System.out.println("\nc中的集合元素为:"+c);
}
}

输出的结果为:
阿里 baidu 解忧杂货店
c中的集合元素为:[阿里, 解忧杂货店]

在使用Iterator遍历Collection时,Iterator并不是把集合本身传给了迭代变量,而是把集合元素的值传给迭代变量,所以修改迭代变量tmp不会改变集合元素本身。

5. Collection 使用泛型遍历

  在上面已经介绍了Collection 的遍历,但是Collection 中的元素默认是Object,遍历时需要强制类型转换,效率较低。JDK1.5之后java支持泛型。下面介绍支持泛型的集合遍历方式。
  java提供了一个迭代器(Iterator)接口:Iterator,主要用来操作java里的集合对象(collection)。迭代器提供了统一的语法进行集合对象(collection)的遍历操作,无需关心集合对象的内部实现方式。Iterator只能向前移动,无法回退。
java的迭代器接口的申明如下:

public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}

  从上面的接口代码可以看到,Iterator接口只有三个无参方法。

方法 返回值 异常 说明
hasNext bool 判断是否还有下一个对象,如果有,则返回true,否则false
next E NoSuchElementException 返回集合的下个值,此方法只能在hasNext方法返回true时调用
remove void IllegalStateException 删除集合的当前值,此方法也只能在hasNext方法返回true时调用

  jdk1.5之后,添加了Iterable接口用于支持foreach的循环。Iterable接口只有一个方法,就是iterator()方法,返回集合的Iterator对象。所有实现Iterable接口的集合都可以使用foreach循环进行遍历。

Iterable的源码如下:

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

5.1 List遍历Demo

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

//这个例子用来演示ArrayList的遍历操作。
public class ArrayListTest {

public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("HAHAHAHA");

//第一种遍历:使用foreach遍历List
for (String str : list) {//可改成for(int i=0;i<list.size();i++)形式
System.out.println(str);
}

//第二种遍历:把链表变为数组相关的内容进行遍历
String[] strArray=new String[list.size()];
list.toArray(strArray);
for(int i=0;i<strArray.length;i++) //可改成foreach(String str:strArray)形式
{
System.out.println(strArray[i]);
}

//第三种遍历:使用迭代器进行相关遍历
Iterator<String> ite=list.iterator();
while(ite.hasNext())//判断下一个元素之后有值
{
System.out.println(ite.next());
}
}
}

5.2 Map遍历Demo

import java.util.*;

public class MapTraverseTest {

public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");

// 第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key="+key+" and value= " + map.get(key));
}

// 第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}

// 第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key="+entry.getKey() + " and value= " + entry.getValue());
}

// 第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
}