集合的体系结构:
Collection :单列集合
Map :双列集合 ---> 以键值对方式出现(相当于C++中的Map)
红色字体为接口, 白色字体为实现类!
List系列集合: 添加的元素有序,可重复,有索引
Set系列集合:添加的元素无序,不重复,无索引
注:这里的有序和无序是看存和取的元素顺序是否一样,一样的话就是有序,不一样的话就是无序
Collection:
定义:
Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的
Collection成员方法:
public boolean add(E, e) //把给定的对象添加到当前集合中
public void clear() //清空集合中的所有元素
public boolean remove(E, e) //把给定的对象在当前的集合中删除
public boolean contains(Object obj) //判断当前集合中是否包含给定的对象
public boolean isEmpty() //判断当前集合是否为空
public int size() //返回集合中元素的个数 或者 是集合的长度
public boolean add(E, e) //把给定的对象添加到当前集合中
-
当我们往List(可重复)中添加元素,方法永远返回true
-
-
当我们往Set(不重复)中添加元素,如果当前要添加的元素在原集合中不存在,方法返回true,添加成功,如果已经存在了,返回false,添加失败
public boolean remove(E, e) //把给定的对象在当前的集合中删除
-
由于Collection中方法是共性的,所以不能通过索引进行删除,只能通过元素的对象进行删除
-
删除成功返回true,反之返回false(要删除的元素在集合中不存在)
public boolean contains(Object obj) //判断当前集合中是否包含给定的对象
细节:方法在底层是依赖equals方法进行判断是否存在,若集合存储的是自定义对象,想通过contains方法判断是否包含,那么在javabean类中,就要对equals方法进行重写
若没有重写,会默认使用Objects类中的equals方法进行判断,而Objects类中的equals方法是依赖地址值进行判断的
Collection的几种遍历方式:
-
迭代器遍历
-
增强for遍历
-
Lambda表达式遍历
1.迭代器遍历
在java中,迭代器遍历不依赖索引,类名叫Iterator,迭代器是集合专用的遍历方式;
Collection获取迭代器对象:
Iterator<E> iterator() //返回迭代器对象,默认指向当前集合的0索引位置
Iterator常用方法:
boolean hasNext(); //判断当前位置是否有元素,有元素返回true,反之返回false
E next(); //获取当前位置元素,并将迭代器对象移向下一位置
hasNext底层源码:
@Override
public boolean hasNext() {
return cursor < a.length; //指针小于数组的长度,表示还未到最后一个元素,返回true
}
next()底层源码:
@Override
public E next() {
int i = cursor;
if (i >= a.length) {
throw new NoSuchElementException();
}
cursor = i + 1; //自动指向下移位置
return a[i]; //返回当前位置
}
创建对象并打印我们可以这样来做:
public static void main(String[] args) {
Collection<Integer> col = new ArrayList<>();
col.add(1);
col.add(2);
col.add(3);
col.add(4);
Iterator<Integer> it = col.iterator(); //创建指针
while (it.hasNext()) { //判断是否有下一元素
Integer num = it.next(); //获取元素,移动指针
System.out.println(num); //打印输出
}
}
总结:
-
若当前位置没有元素还要强行获取,会报错NoSuchElementException
-
迭代器遍历完毕,指针不会复位,如要进行第二次遍历集合,只能再次获取一个新的迭代器对象
-
循环中只能用一次next方法
public static void main(String[] args) { Collection<Integer> col = new ArrayList<>(); col.add(1); col.add(2); col.add(3); col.add(4); col.add(5); Iterator<Integer> it = col.iterator(); while (it.hasNext()) { System.out.printf(it.next() + " "); System.out.printf(it.next() + " "); System.out.println(); } }
代码运行结果:
-
看到NoSuchElementException,知道指针访问到没有元素的位置了,当我们在集合中添加奇数多个元素,而next()方法有偶数个,这样第二个next()方法就会访问到集合中最后一个元素的下一个位置,就报错
所以:
-
hasNext()方法要和next()方法配套使用
-
迭代器遍历时,不能用集合的方法进行增加或删除,要用迭代器中的remove方法
2.增强for遍历
-
增强for循环的底层就是一个迭代器,为了简化迭代器的代码
-
JDK5以后出现的,内部原理是一个Iterator迭代器
-
所有单列集合和数组才能使用增强for进行遍历
格式:
for(元素的数据类型 变量名 : 数组/集合){
//执行的操作
}
IDEA快速生成方式: 数组名/集合名 + for + 回车键
细节:
public static void main(String[] args) {
Collection<Integer> col = new ArrayList<>();
col.add(1);
col.add(2);
col.add(3);
col.add(4);
col.add(5);
for (Integer i : col) { //i在底层就是一个第三方变量,在循环过程中以此表示集合中的每一个元素
i = 10; //修改增强for中的变量的值,不会改变集合中原本的数据
}
for (Integer i : col) {
System.out.println(i); //打印1, 2, 3, 4, 5
}
}
3.Lambda表达式遍历
可以更简单更直接的遍历集合
用法:
可以结合Lambda表达式遍历集合
col.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
forEach方法中形参Consumer实际上是一个函数式接口,所以在传参的时候要传递一个实现类对象,可以使用匿名内部类,new出来的实际上是
{ public void accept(Integer integer) { System.out.println(integer); } }
这个代码块的对象,在类中我们要重写接口的所有抽象方法
底层原理:
就是我们最熟悉不过的for循环
for (int i = 0; modCount == expectedModCount && i < size; i++)
action.accept(elementAt(es, i)); //再把元素交给我们自己重写的accept方法
而其中的elementAt方法的实现逻辑如下:
static <E> E elementAt(Object[] es, int index) {
return (E) es[index]; //就是通过索引来获取集合中的每一个元素
}
代码可以简化如下:
col.forEach(integer-> System.out.println(integer));
总结:
-
Collection是单列集合的顶级父类,所有方法被List和Set系列集合共享
-
常见的成员方法
add, clear, remove, contains, isEmpty, size
-
三种通用的遍历方式:
-
迭代器: 在遍历过程中需要删除元素,可以使用迭代器遍历方式
-
若仅仅想遍历,可以使用增强for或者Lambda表达式
-
List集合:
特点:
-
有序:存和取的元素顺序一样
-
有索引:可以通过索引操作元素
-
可重复:存储的元素可以重复
List集合中的特有方法:
注:Collection的方法List都继承了
1.
void add(int index,E element) //在此集合中的指定位置插入特定的元素
原来索引位置上的元素会依次往后移
2.
E remove(int index) //删除指定索引处的元素,并返回被删除的元素
remove(Object o) //返回值类型 boolean
remove(int index) //返回值类型 Integer
在java中,我们在调用方法的时候,若出现了方法重载,优先调用实参和形参类型一致的那个方法
list.remove(index: 3); //默认使用的就是上面第二种remove方法
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
for (Integer i : list) {
System.out.println(i);
}
list.remove(4); //IDEA中显示如下图:
for (Integer i : list) {
System.out.println(i);
}
}
上述代码会报错: IndexOutOfBoundsException,数组下标越界,验证上述说法;
若我们要使用上面第一种remove方法
Integer i = Integer.valueOf(4); //手动装箱,把基本数据类型4变成Integer类型
list.remove(i);
List系列集合的5种遍历方式:
-
迭代器遍历:在遍历的过程中需要删除元素,请使用迭代器遍历
-
增强for循环/Lambda表达式:仅仅想遍历,可以使用增强for或者Lambda表达式
-
普通for循环:在遍历的时候想操作索引,可以使用普通for遍历
-
列表迭代器:
在遍历的过程中需要添加元素,请使用看列表迭代器
ListIterator<Integer> it = list.listIterator(); //获取了一个列表迭代器对象,里面的指针默认指向0索引 while (it.hasNext()) { Integer it1 = it.next(); if (2 == it1) { list.add(3); //额外添加了一个方法:在遍历的过程中可以添加元素 } }