集合
我们知道Java是面向对象语言,那么万事万物皆是对象,我们需要使用一个容器来存储对象,并且希望对容器中对象进行存储,增加,删除,修改,查询的操作。
集合是一批类,它是一套框架体系,如下图所示:
1.集合为什么要设计出这么多类?
集合分为单列集合和双列集合,单列集合类似于数组存储一组数据,双列集合存储具有关系两列数据,并且有很多不同数据结构的子类,所以设计很多类组合而成
2.集合顶层父类为什么设计成接口而不设计成普通类?
因为我们认为容器中的元素有不同的特点:
a.是否有序 【存储有序,怎么样存进去的就怎样出来】
b.是否唯一
c.是否可以存储null值
d.是否可排序
e.是否安全
f.容器存的效率
数据结构 【数据的存储方式】
针对不同的特点会有不同的实现,那么这个时候父类必须设计成接口,子类根据不同的数据结构和实现方式实现自己的增删查改的功能,所以父类设计为接口。
Collection接口
概述: 单列集合的根接口
特点:
1.作为单列集合的根接口
2.部分集合有序,可重复【List】 部分集合无序,唯一【Set】
3.该接口不会提供具体的实现,如果要创建之,使用多态
Collection常见API
添加
boolean add(E e)
将指定的元素添加到此列表的尾部。
boolean addAll(Collection<? extends E> c)
将指定 collection 中的所有元素都添加到此 collection 中
删除
void clear()
移除此 collection 中的所有元素(可选操作)。
boolean remove(Object o)
从此 collection 中移除指定元素的单个实例
boolean removeAll(Collection<?> c)
移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
修改
因为集合Collection是一个接口,如果能够修改,需要索引,而索引属于List接口的,Colleciton并不能够确定集合是否有序,所以这里不设计修改的方法
遍历
Object[] toArray()
将集合转换成数组
<T> T[] toArray(T[] a)
泛型方法,将集合转换成数组
Iterator iterator()
返回在此 collection 的元素上进行迭代的迭代器。
判断
boolean contains(Object o)
判断集合中是否包含某个元素o
boolean containsAll(Collection<?> c)
如果此 collection 包含指定 collection 中的所有元素,则返回 true。
boolean isEmpty()
如果此 collection 不包含元素,则返回 true。
其他
boolean retainAll(Collection<?> c) 求交集
int size() 获取集合的长度
注意:求交集的方法返回的结果是求交集之后原集合是否发生改变,如果改变了返回true,如果没改变返回false
集合的遍历
1.toArray遍历方式:将集合转换成数组进行遍历
c.add("张三");
c.add("李四");
c.add("王五");
// c.add(c);
System.out.println(c);
Object[] objs = c.toArray();
for (Object obj : objs) {
String s = (String) obj;
System.out.println(s);
}
2.迭代器遍历
// 通过集合创建迭代器对象
Iterator it = c.iterator();
while (it.hasNext()) {
Object obj = it.next();
System.out.println(obj);
}
可能出现的异常:
java.util.NoSuchElementException
异常名称:没有这样的元素异常
产生原因: 在迭代器迭代元素的时候,已经没有元素可以迭代了
解决办法: 在迭代遍历元素之前针对是否有元素做判断
默认集合重写的toString方法
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
迭代器原理
boolean hasNext() 判断是否迭代器中有下一个元素
E next() 获取迭代器中的下一个元素,如果没有下一个元素抛出NoSuchElementException,并且每次调用一次该方法,指针Cursor都会向后移动一个单位
Foreach遍历集合
Foreach遍历集合的格式:
For(元素类型 元素名 : 集合) {
通过元素名操作元素;
}
1.foreach简化遍历
2.Foreach本质还是使用了迭代器
Object obj;
for (Iterator iterator = c.iterator(); iterator.hasNext(); System.out.println(obj))
obj = iterator.next();
3.Foreach遍历集合和while的区别
(1)Foreach遍历之后就会释放迭代器对象,节约内存
(2)While循环遍历集合可读性更强
并发修改异常
java.util.ConcurrentModificationException
异常名称: 并发修改异常
产生原因: 在遍历迭代器对象元素的同时使用集合对象修改了元素
解决办法:
1.可以遍历原集合并且使用原集合修改
泛型toArray
如果是List接口的子集合还可以使用 普通for
2.使用迭代器遍历并且使用迭代器修改
后期可以使用 ListIterator 进行处理
Collection集合去除重复元素
1.创建一个新的集合,然后使用地址传递
(1)如果比较的是系统类,String 不需要重写equals方法
(2)如果比较的是自定义对象,需要自己根据需求重写equals方法
代码示例:
// 1.创建一个新的集合
Collection newC = new ArrayList();
// 2.遍历旧集合,获取到每一个元素
for (Object obj : c) {
// 3.判断在新集合中是否存在该元素
if (!newC.contains(obj)) {
// 4.如果不包含,就存储到新集合中
newC.add(obj);
}
}
// 地址传递
c = newC;
for (Object object : c) {
System.out.println(object);
}
2.使用选择排序思想去除重复元素【详细请看后面的List接口】
List接口
概述: 有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
List 接口常用API
添加
void add(int index, E element)
在列表的指定位置插入指定元素(可选操作)。
boolean addAll(int index, Collection<? extends E> c)
将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。
删除
E remove(int index)
移除列表中指定位置的元素(可选操作)。
修改
E set(int index, E element)
用指定元素替换列表中指定位置的元素(可选操作)。
遍历
E get(int index)
ListIterator listIterator()
返回此列表元素的列表迭代器(按适当顺序)。
ListIterator listIterator(int index)
返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
获取
int indexOf(Object o)
返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
int lastIndexOf(Object o)
返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
List subList(int fromIndex, int toIndex)
返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
List接口的遍历方式
代码实例:
List<String> list = new ArrayList<String>();
list.add("林冲");
list.add("武大郎");
list.add("潘金莲");
list.add("西门庆");
list.add("武松");
list.add("李逵");
list.add("宋江");
list.add("卢俊义");
list.add("时迁");
// 泛型toArray 来自于Collection
String[] strs = list.toArray(new String[] {});
for (String s : strs) {
System.out.println(s);
}
System.out.println("=================");
// 迭代器 来自于Collection
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("=================");
// 迭代器的for循环版本
for(Iterator<String> iterator = list.iterator();
iterator.hasNext(); System.out.println(iterator.next())) ;
System.out.println("=================");
// foreach遍历
for (String s: strs) {
System.out.println(s);
}
System.out.println("=================");
/*System.out.println(list.get(0));
System.out.println(list.get(1));
System.out.println(list.get(2));
System.out.println(list.get(3));
System.out.println(list.get(4));*/
// 普通for遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
/*for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (s.equals("武大郎")) {
list.remove("潘金莲");
}
}
System.out.println(list);*/
System.out.println("=================");
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
String s = lit.next();
System.out.println(s);
}
System.out.println("=================");
// 如果需要逆向遍历,必须先正向遍历
// System.out.println(lit.previous());
while (lit.hasPrevious()) {
String s = lit.previous();
System.out.println(s);
}
System.out.println("=================");
// ListIterator<String> listIterator = list.listIterator(list.size());
/*while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}*/
/*while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}*/
List<String> subList = list.subList(1, 5);
ListIterator<String> listIterator = subList.listIterator(subList.size());
while(listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
System.out.println("=================");
ListIterator<String> listIterator2 = list.listIterator();
while (listIterator2.hasNext()) {
String s = listIterator2.next();
if (s.equals("宋江")) {
// list.remove("潘金莲");
listIterator2.remove();
}
}
System.out.println(list);
ArrayList类
特点:
1.底层数据结构是数组
2.有索引,方便查询和修改,有序的
3.可以存储null值
4.可以存储重复元素
5.修改和查询的效率高,添加和删除的效率低
6.线程不安全,效率高
7.不可以排序的,如果想要排序可以使用 Collections的sort方法进行排序
常见方法都来自于 Colllection和List
如何使用ArrayList进行去除重复元素?
1.创建新的集合
2.选择排序思想去除重复元素
概述: List 接口的大小可变数组的实现
Set接口
概述: 一个不包含重复元素的 collection
特点:
1.元素唯一
2.元素无序
3.元素可以存储null值,但是null值不能重复
常见方法全部来自于 Collection
HashSet类
概述: 此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
特点: 底层数据结构是哈希表结构