集合类概述
java.util包中的集合类就像一个装有多个对象的容器,提到容器就不难想到数组,数组与集合的不同之处在于:数组的长度是固定的,集合的长度是可变的;数组既可以存放基本数据类型大数据,又可以存放对象,集合只能存放对象。集合类包括List集合、Set集合和Map集合,其中List与Set继承了Collection接口,且List接口、Set接口和Map接口还提供了了不同的实现类,List集合、Set集合和Map集合大的继承关系如下图:
说明:由上图可知,Set接口和List接口都继承于Collection接口,Collection接口虽然不能直接被使用,但提供了操作合集以及集合中元素的方法,且Set接口都可以调用Collection接口中的方法,Collection接口的常用方法及说明如下表;
方法 | 功能描述 |
---|---|
add(Object e) | 将指定的对象添加到当前合集内 |
remove(Object o) | 将指定的对象从当前集合内移除 |
isEmpty() | 返回Boolean值,用于判断当前合集是否为空 |
iterator() | 返回用于遍历集合内元素的迭代器 |
size() | 返回int型值,获取当前集合中元素的个数 |
List集合
List集合包括List接口以及List接口的所有实现类,List集合中的元素允许重复,且各元素的顺序就是添加元素的顺序,类似java数组,用户可以通过索引(元素在集合中位置)访问集合中的元素
List接口
List接口继承了Collection接口,因此可以使用Collection接口中的所有方法,此外,List接口还定义了两个非常重要的方法,如下表:
方法 | 功能描述 |
---|---|
get(int index) | 获得指定索引位置上的元素 |
set(int index,Object obj) | 将集合中指定索引位置的对象修改为指定的对象 |
List接口的实现类
因为List接口不能直接被实例化,所以java提供了List接口的实现类,其中最常用的实现类是ArrayList类与LinkedList类。
类名 | 功能描述 |
---|---|
ArrayList | 以数组的形式保存集合中的元素,能够根据索引位置随机且快速地访问集合中的元素 |
LinkedList | 以链表结构保存集合中的元素,随机访问集合中元素的性能较差,但向集合中插入元素和删除元素的性能出色 |
分别使用ArrayList类和LinkedList类实例化List集合的关键代码如下:
List<E> list = new ArrayList<E>();
List<E> list2 = new LinkedList<E>();
注意:其中,E代表元素类型,例如,如果集合中的元素均为字符串类型,那么E即为String类型,E也可以不用写。
下面讲解List集合的常用方法,代码如下:
import java.util.*;
public class Demo {
public static void main(String[] args) { // 主方法
List<String> list = new ArrayList<>(); // 创建集合对象
list.add("a"); // 向集合添加元素
list.add("b");
list.add("c");
list.remove(0); //删除索引为0的字符串
list.set(1, "123"); //将索引为1的字符串的值更改为字符串123
list.size(); //计算数组的大小
for (int j = 0; j < list.size(); j++) { // 循环遍历集合
System.out.println(list.get(j)); // 获取指定索引处的值
}
}
}
Iterator迭代器
在上面实例当中使用了for循环遍历List集合中的元素,那么还有没有其他遍历集合中元素的方法呢?,在Java包中提供了一个Iterator接口,Iterator接口是一个专门对集合进行迭代的迭代器,其常用方法如下表:
方法 | 功能描述 |
---|---|
hasNext() | 如果仍有元素可以迭代,则返回true |
next() | 返回迭代的下一个元素 |
remove() | 从迭代器指向的Collection中移除迭代器返回的最后一个元素(可选操作) |
注意:Iterator的next()方法返回值类型是Object
使用iterator迭代器时,需要使用Collection接口中的iterator方法创建一个iterator对象,下面将讲解迭代器用法,代码如下:
import java.util.*; //导入java.util包,其他实例都要添加该语句
public class Demo { // 创建类IteratorTest
public static void main(String args[]) {
Collection<String> list = new ArrayList<>(); // 实例化集合类对象
list.add("a"); // 向集合添加数据
list.add("b");
list.add("c");
Iterator<String> it = list.iterator(); // 创建迭代器
while (it.hasNext()) { // 判断是否有下一个元素
String str = (String) it.next(); // 获取集合中元素
System.out.println(str);
}
}
}
返回结果:
Set集合
Set集合由Set接口和Set接口的实现类组成,Set集合中的元素不按特定的方式排序,只是简单地被存放在集合中,但Set集合中的元素不能重复
Set接口
Set接口继承了Collection接口,因此可以使用Collection接口中的所有方法,由于Set集合中的元素不能重复,因此在向Set集合中添加元素时,需要先判断新增元素是否已经存在于集合中,在确定是否执行添加操作,例如,向使用HashSet实现类创建的Set集合中添加元素的流程图如下:
Set接口的实现类
Set接口常用的实现类有HashSet类与TreeSet类,分别如下:
- HashSet是Set接口的一个实现类,他不允许有重复元素;
- TreeSet类不仅实现了Set接口,还是实现了java.util.SortedSet接口,因此在遍历使用TreeSet类实现的Set集合中的元素时,会默认地将元素按升序排列,在创建TreeSet类对象时,通过使用Comparator接口,还是可以实现定制排序,例如降序排列;
如果想指定TreeSet的排序规则,可以在实例化TreeSet对象时,将一个已经写好的比较器作为构造方法参数传入,或者让TreeSet中的所有元素都实现Compareble接口。TreeSet类除了可以使用Collection接口中的方法以外,还提供了了一些其他操作集合中元素的方法,TreeSet类增加的方法如下表:
方法 | 功能描述 |
---|---|
first() | 返回此Set中当前第一个(最低)元素 |
last() | 返回此Set中当前第一个(最高)元素 |
comparator() | 返回对此Set中的元素进行排序的比较器,如果此Set使用自然顺序,则返回Null |
headSet(E toElement) | 返回一个新的Set合集,新合集是toElement(不包含)之前的所有对象 |
subSet(E fromElement,E formElement) | 返回一个新的Set集合,是fromElement(包含)对象与fromElement(不包含对象之间的所有对象) |
tailSet(E fromElement) | 返回一个新的Set合集,新合集包含对象fromElement(包含)之后的所有对象 |
说明:HashSet类和TreeSet类都是Set接口的实现类,他们都不允许有重复元素,但HashSet类在遍历集合中的元素时不关心元素的顺序,而TreeSet类则会按自然顺序(升序排列)遍历集合中的元素
下面实例讲解HashSet类和TreeSet类,代码如下:
首先创建一个比较器(person)类,TreeSet类默认是升序,我用比较器进行倒序,代码如下:
import java.util.Comparator;
public class Person implements Comparable{
int i;
public Person(int i) {
super();
this.i = i;
}
public String toString() {
return "Person [i=" + i + "]";
}
public int compareTo(Object arg0) {
Person p = (Person)arg0; //将传过来的值进行向下转型
if(this.i < p.i) { //如果值this.i大于p.i值会升序反之会倒序
return 1;
}
if(this.i > p.i) {
return -1;
}
return 0;
}
}
说明:Comparetor接口,即比较器,他提供一个抽象方法compare(T ol,T o2),这个方法指定两个对象的比较规则,如果o1大于o2,方法会返回正数(通常为+1);如果o1等于o2,方法返回0;如果o1等于o2,方法返回负数(通常为-1)
在创建Demo类,代码如下:
import java.util.*;
public class Demo {
public static void main(String args[]) {
//创建TreeSet类
Set treeset = new TreeSet();
System.out.println("以下是TreeSet类遍历的数组并将数组进行倒序排列");
Person p1 = new Person(1);
Person p2 = new Person(2);
Person p3 = new Person(3);
treeset.add(p1);
treeset.add(p2);
treeset.add(p3);
//创建迭代器并遍历数组
Iterator<Integer> it = treeset.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
//创建HashSet类
Set hashset = new HashSet();
System.out.println("以下是HashSet类遍历的数组");
hashset.add(4);
hashset.add(3);
hashset.add(2);
hashset.add(1);
//创建迭代器并遍历数组
Iterator it2 = hashset.iterator();
while(it2.hasNext()) {
System.out.println(it2.next());
}
}
}
返回结果如下图:
Map集合
在程序中,如果想存储具有映射关系的数据,那么就需要使用Map合集了,Map合集由Map接口和Map接口的实现类组成。
Map接口
Map接口虽然没有继承Collection接口,但提供了key到value的映射关系,Map接口中不能包含相同的key,并且每个key只能映射一个value,Map接口常用方法如下表:
方法 | 功能描述 |
---|---|
put(object key,Object value) | 向集合中添加指定的key与value的映射关系 |
containsKey(object key) | 如果次映射包含指定key的映射关系,则返回true |
containsValue(Object value) | 如果此映射将一个或多个key映射到指定值,则返回true |
get(object key) | 如果存在指定的key对象,则返回该对象对应的值,否则返回null |
keySet() | 返回该集合中的所有key对象形成的Set集合 |
values() | 返回该集合中所有值对象形成的Collection集合 |
Map接口实现类
Map接口常用的实现类有HashMap类和TreeMap类两种,分别如下:
- HashMap类时Map接口实现的类,HashMap类虽然能够通过哈希表快速查找其内部的映射关系,但不保证映射关系顺序,在key-value对(键值对)中,由于key不能重复,所以最多只有一个key为null,但可以有无数多个value为null
- TreeMap类不仅实现了Map接口,还实现了java.util.SorteMap接口,由于使用TreeMap类实现的Map集合存储key-value对时,需要根据key进行排序,所以key不能为null
建议使用HashMap类实现Map集合,因为由HashMap类实现的Map集合添加和删除映射关系的效率较高;而如果希望Map集合中的元素存在一定的顺序,应该使用TreeMap类实现Map集合
下面实例讲解Map用法:
import java.util.*;
public class Demo {
public static void main(String args[]) {
//创建HashMap类
Map map = new HashMap();
//想Map集合添加数据
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
//构建Map集合中所有key的Set集合
Set key = map.keySet();
//创建迭代器
Iterator it = key.iterator();
//遍历key值
System.out.println("遍历key值");
while(it.hasNext()) {
System.out.println(it.next());
}
//构建Map集合中所有value值的集合
Collection value = map.values();
//创建迭代器
Iterator it2 = value.iterator();
//遍历value值
System.out.println("遍历value值");
while(it2.hasNext()) {
System.out.println(it2.next());
}
}
}
返回结果:
集合的使用场合
List集合、Set集合和Map集合,那么在实际开发中,具体何时应该选择哪种集合呢?这里总结了以下原则:
- List集合:List集合关注的索引,List集合中的元素是有存放顺序的,例如一个学生的成绩,成绩可以重复,就可以使用List集合存放
- Set集合:Set集合关注的是唯一性,它的值不允许重复,例如每个班学生的学号,每个学生的学号是不能重复的
- Map集合:Map集合关注的是唯一标识符(key),它将唯一的建映射到某个元素,例如每个班学生的学号与姓名的映射,每个学号对应一个学生的名字,学号是不能重复的,但是学生的姓名有可能重复