Java基础学习笔记11——集合(Collection)接口
目录
1.5.3、迭代器Iterator引发并发修改异常(ConcurrentModificationException)
集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以发生改变。
集合类的体系结构:
![](https://img-blog.csdnimg.cn/e48134509305446a9d113929a68c5249.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZWK5ZmiMTIzMQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
1、Collection集合
Collection接口在java.util包下,使用前需要导包。
1.1、Collection集合概述
- 是单列集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素;
- JDK不提供此接口的任何直接实现,它提供更具体地子接口(如Set和List)实现。
1.2、创建Collection集合的对象
- 多态的方式;
- 具体的实现类(如ArrayList等)。
1.3、Collection集合常用方法
方法名 | 描述 |
---|---|
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定的元素 |
boolean inEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
1.4、Collection集合的遍历
Iterator:迭代器,集合的专用遍历方式
- Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到;
- 迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的。
Iterator中的常用方法:
- E next():返回迭代中的下一个元素;
- boolean hasNext():如果迭代具有更多元素,则返回true。
Iterator不允许在遍历过程中修改集合。
代码演示:
package IterPackage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
//创建集合对象
Collection<String> c = new ArrayList<String>();
//添加元素
c.add("Hello");
c.add("World");
c.add("Java");
//遍历集合
//Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到;
Iterator<String> it = c.iterator(); //多态,返回的是迭代器接口的实现类对象
//boolean hasNext():如果迭代具有更多元素,则返回true。
while(it.hasNext()){
System.out.println(it.next()); //E next():返回迭代中的下一个元素;
}
}
结果:
Hello
World
Java
1.5、Collection的子接口——List集合
List接口在java.util包下,使用前需要导包。List接口继承自Collection接口。
- List是有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素;
- 与集合不同,列表通常允许重复的元素。
1.5.1、List集合的特点
- 有序:存储和取出的元素顺序一致;
- 可重复:存储的元素可以重复。
1.5.2、List集合的特有方法
方法名 | 描述 |
---|---|
void add(int index, E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index, E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
1.5.3、迭代器Iterator引发并发修改异常(ConcurrentModificationException)
产生原因:Iterator迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致。
解决方案:用for循环遍历,然后用集合对象做对应的操作即可。
1.5.4、ListIterator(列表迭代器)
ListIterator(迭代器Iterator的子类)通过List集合的listIterator()方法得到,所以说它是List集合特有的迭代器。
ListIterator允许程序员沿任一方向遍历列表,在迭代期间修改列表,并获取列表中迭代器的当前位置。
ListIterator中的常用方法:
- E next():返回迭代中的下一个元素;
- E previous():返回列表中的上一个元素;
- boolean hasNext():如果迭代具有更多元素,则返回true;
- boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true;
- void add(E, e):将指定的元素插入列表。
1.5.5、增强for循环
增强for:简化数组和Collection集合的遍历。
- 实现Iterable接口的类允许其对象成为增强型for语句的目标;
- 它是JDK5之后出现的,其内部原理是一个Iterator迭代器。
增强for的格式:
//格式
for(元素数据类型 变量名:数组或者Collection集合){ //内部原理是一个Iterator迭代器
//在此处使用变量即可,该变量就是元素
}
//范例
int[] arr = {1, 2, 3, 4, 5};
for(int i:arr){
System.out.println(i);
}
1.5.6、List集合的实现类(子类)
List集合的常用子类:ArrayList, LinkedList 。
- ArrayList的底层结构是数组,查询快,增删慢。
- LinkedList的底层数据结构是链表,查询慢,增删快。
二者的用法基本相同。
1、ArrayList类
ArrayList在java.util包下,使用前需要导包。ArrayList的底层结构是数组,查询快,增删慢。
ArrayList<E>:
- 可调整大小的数组实现;
- <E>:是一种特殊的数据类型,泛型。
在出现E的地方我们使用数据类型替换即可。举例:ArrayList<String>。
1)ArrayList集合的构造方法和添加方法
方法名 | 说明 |
---|---|
public ArrayList() | 创建一个空的集合对象 |
public boolean add(E e) | 将指定的元素追加到此集合的末尾 |
public void add(int index, E element) | 在此集合中的指定位置插入指定的元素 |
代码演示:
package myPackage;
import java.util.ArrayList;
public class TestArrayList {
public static void main(String[] args) {
//创建一个集合对象
ArrayList<String> array = new ArrayList<>();
//ArrayList<String> arrat = new ArrayList<String>(); //第二种方式
//添加元素到集合末尾。public boolean add(E e):将指定的元素追加到此集合的末尾
System.out.println(array.add("Hello"));
array.add("World");
System.out.println("array:"+array);
//在集合的指定位置添加元素。public void add(int index, E element):在此集合中的指定位置插入指定的元素
array.add(1,"Java");
System.out.println("array:"+array);
}
结果:
true
array:[Hello, World]
array:[Hello, Java, World]
2)ArrayList集合的常用方法
方法名 | 说明 |
---|---|
public boolean remove(Object o) | 删除指定的元素,返回删除是否成功 |
public E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
public E set(int index, E element) | 修改指定索引处的元素,返回被修改的元素 |
public E get(int index) | 返回指定索引处的元素 |
public int size() | 返回集合中的元素的个数 |
代码演示:
package myPackage;
import java.util.ArrayList;
public class TestArrayList {
public static void main(String[] args) {
//创建一个集合对象
ArrayList<String> array = new ArrayList<>();
//添加元素
array.add("Hello");
array.add("World");
array.add("Java");
array.add("OK");
System.out.println("原集合:" + array);
//public boolean remove(Object o):删除指定的元素,返回删除是否成功
System.out.println("删除World:" + array.remove("World") + "," + "结果为"+array);
System.out.println("删除dsad:" + array.remove("dsad") + "," + "结果为"+array);
//public E remove(int index):删除指定索引处的元素,返回被删除的元素
System.out.println("删除索引为1的元素:" + "删除了" + array.remove(1) + "," + "结果为"+array);
//public E set(int index, E element):修改指定索引处的元素,返回被修改的元素
System.out.println("修改索引为0的元素为change:" + "修改了" + array.set(0,"change") + "," + "结果为"+array);
//public E get(int index):返回指定索引处的元素
System.out.println("返回索引为0的元素:" + "返回了了" + array.get(0) + "," + "结果为"+array);
//public int size():返回集合中的元素的个数
System.out.println("集合中元素个数为:" + array.size());
}
}
结果:
原集合:[Hello, World, Java, OK]
删除World:true,结果为[Hello, Java, OK]
删除dsad:false,结果为[Hello, Java, OK]
删除索引为1的元素:删除了Java,结果为[Hello, OK]
修改索引为0的元素为change:修改了Hello,结果为[change, OK]
返回索引为0的元素:返回了了change,结果为[change, OK]
集合中元素个数为:2
2、LinkedList 类
LinkedList的底层数据结构是链表,查询慢,增删快。用法与ArrayList基本相同。
1)LinkedList集合的特有功能
方法名 | 描述 |
---|---|
public void addFirst(E e | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
1.6、Collection的子接口——Set集合
1.6.1、Set集合的特点
- 不包含重复元素;
- 没有带索引的方法,所以不能使用普通for循环遍历。
1.6.2、哈希值
哈希值是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。
Object类中有一个方法可以获取对象的哈希值:
//返回对象的哈希码值
public int hashCode();
对象的哈希值特点:
- 同一个对象多次调用hashCode()方法返回的哈希值是相同的;
- 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法(该方法可在元素类中自动生成),可以实现让不同对象的哈希值相同。
1.6.3、哈希表
- JDK8之前,底层采用数组+链表实现,可以说是一个元素为链表的数组;
- JDK8以后,在长度比较长的时候,底层实现了优化。
1.6.4、Set集合的实现类(子类)
1、HashSet类
1)HashSet集合的特点:
- 底层数据结构是哈希表;
- 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致;
- 没有带索引的方法,所以不能使用普通for循环遍历(可使用增强for循环);
- 由于是Set集合,所以是不包含重复元素的集合。
2、LinkedHashSet类
1)LinkedHashSet集合的特点:
- 哈希表和链表实现的Set接口,具有可预测的迭代次序;
- 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的;
- 由哈希表保证元素唯一,也就是说没有重复的元素。
3、TreeSet类(间接实现Set接口)
1)TreeSet集合的特点:
构造方法 | 描述 |
---|---|
TreeSet() | 根据其元素的自然排序进行排序 |
TreeSet(Comparator comparator) | 根据指定的比较器进行排序 |
- 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法:
- 没有带索引的方法,所以不能使用普通for循环遍历(可使用迭代器和增强for遍历);
- 由于是Set集合,所以不包含重复元素。
2)自然排序Comparable的使用:
需求:
- 存储学生对象并遍历,创建TreeSet集合使用无参构造方法;
- 按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序。
结论:
- 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的;
- 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法;
- 重写方法时,一定要注意排序规则,必须按照要求的主要条件和次要条件来写。
代码实现:
package TSPackage;
public class Student implements Comparable<Student>{
private String name; //姓名
private int age; //年龄
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Student s) {
//return 0; //该返回值说明新添加的元素是重复的
//return 1; //按照存储顺序添加元素
//return -1; //按照存储倒序添加元素
//按照年龄从小到大排序
int num = this.age - s.age; //按年龄升序
//年龄相同时,按照姓名的字母顺序排序
return num == 0 ? this.name.compareTo(s.name) : num; //String类有compareTo()方法
}
}
package TSPackage;
import java.util.TreeSet;
public class Test {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student> ts = new TreeSet<Student>();
//创建学生对象
Student s1 = new Student("zhangsan",20);
Student s2 = new Student("lisi",19);
Student s3 = new Student("wangwu",18);
Student s4 = new Student("zhaoliu",19);
Student ss = new Student("zhaoliu",19);
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(ss);
//遍历集合
for(Student s : ts){
System.out.println(s.getName()+","+s.getAge());
}
}
}
结果:
wangwu,18
lisi,19
zhaoliu,19
zhangsan,20
3)比较器排序Comparator的使用
需求:
- 存储学生对象并遍历,创建TreeSet集合使用带参构造方法;
- 按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序。
结论:
- 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的;
- 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1, T o2)方法;
- 重写方法时,一定要注意排序规则,必须要按照要求的主要条件和次要条件来写。
代码实现:
package TSPackage;
public class Student {
private String name; //姓名
private int age; //年龄
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package TSPackage;
import java.util.Comparator;
import java.util.TreeSet;
public class Test {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() { //匿名内部类
@Override
public int compare(Student s1, Student s2) {
//return 0; //该返回值说明新添加的元素是重复的
//return 1; //按照存储顺序添加元素
//return -1; //按照存储倒序添加元素
//按照年龄从小到大排序
int num = s1.getAge() - s2.getAge(); //按年龄升序
//年龄相同时,按照姓名的字母顺序排序
return num == 0 ? s1.getName().compareTo(s2.getName()) : num; //String类有compareTo()方法
}
});
//创建学生对象
Student s1 = new Student("zhangsan",20);
Student s2 = new Student("lisi",19);
Student s3 = new Student("wangwu",18);
Student s4 = new Student("zhaoliu",19);
Student ss = new Student("zhaoliu",19);
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(ss);
//遍历集合
for(Student s : ts){
System.out.println(s.getName()+","+s.getAge());
}
}
}
结果:
wangwu,18
lisi,19
zhaoliu,19
zhangsan,20
2、Map集合
2.1、Map集合概述
- Interface Map<K,V> K:键的类型;V:值的类型
- 将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值。
创建Map集合的对象:
- 多态的方式;
- 具体的实现类(如HashMap)。
2.2、Map集合的常用功能
方法名 | 描述 |
---|---|
V put(K key, V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean congtainsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
代码演示:
package GPackage;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
//创建集合对象
Map<Integer,String> map = new HashMap<Integer,String>();
//V put(K key, V value):添加元素
map.put(2,"张三");
map.put(4,"李四");
map.put(6,"王五");
System.out.println(map);
System.out.println("--------");
//V remove(Object key):根据键删除键值对元素,若找不到键值则返回null
System.out.println(map.remove(4));
System.out.println(map);
System.out.println("--------");
//void clear():移除所有的键值对元素(慎重使用)
//boolean containsKey(Object key):判断集合是否包含指定的键
System.out.println(map.containsKey(6));
System.out.println("--------");
//boolean congtainsValue(Object value):判断集合是否包含指定的值
System.out.println(map.containsValue("李四"));
System.out.println("--------");
//boolean isEmpty():判断集合是否为空
System.out.println(map.isEmpty());
System.out.println("--------");
//int size():集合的长度,也就是集合中键值对的个数
System.out.println(map.size());
}
结果:
{2=张三, 4=李四, 6=王五}
--------
李四
{2=张三, 6=王五}
--------
true
--------
false
--------
false
--------
2
2.3、Map集合的获取功能
方法名 | 说明 |
---|---|
V get(Object key) | 根据键获取值 |
Set<K> keySet() | 获取所有键的集合 |
Collection<V> values() | 获取所有值的集合 |
Set<Map.Entry<K,V>> entrySet() | 获取所有键值对对象的集合 |
代码演示:
package GPackage;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
//创建集合对象
Map<Integer,String> map = new HashMap<Integer,String>();
//V put(K key, V value):添加元素
map.put(2,"张三");
map.put(4,"李四");
map.put(6,"王五");
System.out.println(map);
System.out.println("--------");
//V get(Object key):根据键获取值
System.out.println(map.get(2));
//Set<K> keySet():获取所有键的集合
System.out.println(map.keySet());
//Collection<V> values():获取所有值的集合
System.out.println(map.values());
//Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合
}
}
结果:
{2=张三, 4=李四, 6=王五}
--------
张三
[2, 4, 6]
[张三, 李四, 王五]
2.4、Map集合的遍历
2.4.1、遍历方式1
package GPackage;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
//创建集合对象
Map<Integer, String> map = new HashMap<Integer, String>();
//V put(K key, V value):添加元素
map.put(2, "张三");
map.put(4, "李四");
map.put(6, "王五");
System.out.println(map);
System.out.println("--------");
//获取所有键的集合,用keySet()方法实现
Set<Integer> keySet = map.keySet();
//遍历键的集合,获取到每一个键,用增强for实现
for (Integer key : keySet) {
//根据键去找值,用get(Object key)方法实现
System.out.println(key + "," + map.get(key));
}
}
}
结果:
{2=张三, 4=李四, 6=王五}
--------
2,张三
4,李四
6,王五
2.4.2、遍历方式2
package GPackage;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
//创建集合对象
Map<Integer, String> map = new HashMap<Integer, String>();
//V put(K key, V value):添加元素
map.put(2, "张三");
map.put(4, "李四");
map.put(6, "王五");
System.out.println(map);
System.out.println("--------");
//获取所有键值对对象的集合
Set<Map.Entry<Integer,String>> eSet = map.entrySet();
//遍历键值对对象的集合,得到每一个键值对对象
for(Map.Entry<Integer,String> me : eSet){
//根据键值对对象获取键和值
System.out.println(me.getKey()+","+me.getValue());
}
}
}
结果:
{2=张三, 4=李四, 6=王五}
--------
2,张三
4,李四
6,王五
2.5、Map集合的实现类(子类)
HashMap和TreeMap,使用方法参照上述代码。
3、Collections类
3.1、Collections类概述
Collections在java.util包下,故使用时需要导包。Collections是一个具体的类(Collection是一个单列集合的顶层接口),仅由静态方法组成,是针对集合操作的工具类。
3.2、Collections类的常用方法
方法名 | 描述 |
---|---|
public static <T extends Comparable<? super T>> void sort(List<T> list) | 将指定的列表按升序排列 |
public static void reverse(List<?> list) | 反转指定列表中元素的顺序 |
public static void shuffle(List<?> list) | 只用默认的随机源随机排列指定的列表 |
代码演示:
package GPackage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class Test {
public static void main(String[] args) {
//创建集合对象
List<Integer> list = new ArrayList<Integer>();
//添加元素
Random rand = new Random();
for (int i = 0; i < 10; i++) {
list.add(rand.nextInt(100));
}
System.out.println("原列表:" + list);
//public static <T extends Comparable<? super T>> void sort(List<T> list):将指定的列表按升序排列
Collections.sort(list);
System.out.println("排序后:" + list);
//public static void reverse(List<?> list):反转指定列表中元素的顺序
Collections.reverse(list);
System.out.println("反转后:" + list);
//public static void shuffle(List<?> list):只用默认的随机源随机排列指定的列表
Collections.shuffle(list);
System.out.println("随机置换后:" + list);
}
}
结果:
原列表:[90, 66, 87, 60, 65, 49, 12, 44, 31, 86]
排序后:[12, 31, 44, 49, 60, 65, 66, 86, 87, 90]
反转后:[90, 87, 86, 66, 65, 60, 49, 44, 31, 12]
随机置换后:[87, 12, 86, 31, 49, 66, 90, 44, 60, 65]