目录
通过元素自身实现比较规则(可参考笔记12中对Comparable的描述)
Collection集合的遍历——迭代器(Iterator)
Stack中的 int search(Object o)方法
Collection
List
LinkedList ArrayList Vector
Stack(Vector的子类)
Collection集合概述和使用
Collection集合概述:
- 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
- JDK不提供此接口的任何直接实现,它提供更具体的子接口(Set和List)实现
创建Collection集合的对象:
- 多态
- 具体的实现类ArrayList
Collection<E> 集合名字=new ArrayList<String>();
方法使用例子:
boolean add(E e)
boolean remove(Object o)
void clear()
boolean contains(Object o)
boolean isEmpty()
int size()
List集合概述和特点
List集合概述:
- 有序集合(也称为序列),用户可以精确控制列表每个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素。
- 与Set集合不同,列表通常允许重复的元素
List集合特点:
- 有序:存储和取出的元素顺序一致
- 可重复:存储的元素可以重复
注:索引和数组一样,都是从0开始记。
List集合的子类
ArrayList:
底层数据结构是数组,查询快,增删慢
LinkedList:
底层数据结构是链表,查询慢,增删快
Vector:
Set集合概述和特点
Set接口继承自Collection,Set接口中没有新增方法,方法和Collection保持完全一致。
set集合最常用的实现类有HashSet、TreeSet和LinkedHashSet;
- 无序(对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致)
- 不重复
- 没有带索引的方法,所以不能使用普通for循环遍历,只能遍历查找
HashSet集合
- 线程不安全
-
集合元素可以是null,但只能放入一个null
- 采用哈希算法实现,底层数据结构是哈希表(HashMap)
无序:元素在数组中存放的时候,并不是有序存放也不是随机存放,而是对元素的哈希值进行运算决定元素在数组中的位置。
不重复:采用哈希算法进行计算得到相同的在数组中的位置时,会调用equals()方法比较两个元素是否一样,如果相同那么就不添加。如果不相同,那么就使用单向链表保存该元素。
HashSet集合保证元素唯一性的源码分析
把对象存储在容器里面,在遍历容器时,需要对对象所属的类的toString方法进行重写。
TreeSet集合的概述和特点
TreeSet是一个可以对元素进行排序(而HashSet则不支持)的容器,底层实际是用TreeMap实现的,内部维持了一个简化版的TreeMap,通过Key来存储Set的元素。TreeSet内部需要对存储的元素进行排序,因此,我们需要给定排序规则。
TreeSet排序规则实现方式有如下两种
-
通过元素自身实现比较规则(可参考笔记12中对Comparable的描述)
集合存储的对象所属的类需要实现Comparable接口中的CompareTo方法,该方法用来定义比较规则,TreeSet通过调用该方法来完成对元素的排序处理
对于CompareTo方法
升序时 this在前面,降序时 this在后面
这里TreeSet用的无参构造,自动从小到大排序,判断大小的标准是compareTo的返回值,如果返回值是1就放在后面,返回值是-1就放在前面。只说1是正序是不对的
-
通过比较器指定比较规则
通过比较器定义比较规则时,我们需要单独创建一个 比较器,比较需要实现Comparator接口中的Compare方法来定义比较规则,在实例化TreeSet时将比较器对象交给TreeSet来完成元素的排序处理,此时元素自身就不需要实现比较规则了
例如:年龄由小到大排序,如果年龄相同,咋按照姓名来排序
注意此处:在实例化TreeSet时将比较器对象交给TreeSet来完成元素的排序处理
LinkedHashSet集合概述和特点
Collection集合的遍历——迭代器(Iterator)
Iterator:迭代器,集合的专用遍历方式,无论是Set还是List都可以用
- Iterator<E> iterator() ; 返回此集合中元素的迭代器,通过集合的iterator()方法得到
Collection<String> c=new ArrayList<String>(); //创建集合对象
Iterator<String> it=c.iterator();
- 迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的
iterator中的常用方法
方法 | 说明 |
E next() | 获取当前游标所在位置的元素,并将游标移动到下一个位置 |
boolean hasNext() | 判断游标当前位置是否有元素,如果有,返回true,否则返回false |
void remove() | 删除游标当前位置的元素,在执行完next后,该操作只能执行一次 |
并发修改异常
并发修改异常
- ConcurrentModificationException
产生调用
- 迭代器的调用中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致
解决方案
- 用for循环遍历,然后用集合对象做对应的操作即可
无论是while循环还是for循环,都不要在循环里面对容器进行添加元素的操作,删除元素可以,但是最好不要再循环里面对元素进行删除,最好是在循环外面进行删除。
ListIterator(列表迭代器)
- Collection接口实现了Iterator接口,所有的容器实现类都可以使用Iterator的方法。
但是ListIterator这个类型,只是适合List使用
- iterator迭代器不能增删列表元素 但ListIterator迭代器可以
- 通过List集合的listiterator()方法得到,所以说它是List集合特有的迭代器
ListIterator<E> 列表迭代器名称=List集合名称.listiterator();
- 用于允许程序沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
ListIterator中的常用方法
方法名 | 作用 |
E next() | 返回迭代中的下一个元素 |
boolean hasNext() | 如果迭代具有更多元素,则返回true |
E previous() | 返回列表中的上一个元素 |
boolean hasPrevious() | 如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true |
void add(E e) | 将指定元素插入列表 |
迭代器就是只实现功能,列表迭代器(ListIterator)能实现功能并且能更新列表长度
在for循环中,对ArrayList容器中的元素进行增删操作后,List的大小会发生更新,删除索引为2的元素后,原来索引为3的元素会移动到索引为2的位置。这样的操作在for循环里面,没循环一次就要删除一个索引为2的元素,但是我们的目的是要把c从集合里面删除掉,
下面的代码进行了改进,实现了删除ArrayList容器中的c元素后,还能用for循环继续往下循环输出元素
只在迭代得到的元素的内容是“c”时,才会对容器中的元素进行删除
集合的使用步骤
练习:用 List集合存储学生对象并遍历
需求:创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合
思路:
- 定义学生类
- 创建List集合对象
- 创建学生对象
- 把学生添加到集合
- 遍历集合
迭代器方式:集合特有的遍历方式
普通for循环:带有索引的遍历方式
增强for循环:最简单的遍历方式
练习:用HashSet集合存储学生对象并遍历
放入集合的对象中,有两个对象的内容一致
这时候就要重写hashCode()和equals()方法了
Collection的常用方法
方法 | 说明 |
boolean add(Object obj) | 添加一个指定元素到列表末尾 |
boolean addAll(Object Collection<?> c) | 添加一个集合的元素到列表末尾(并集) |
void clear() | 删除所有元素 |
boolean remove(Object obj) | 删除列表中出现的首个指定元素 |
boolean removeAll(Collection<?> c) | 删除指定集合包含集合c的元素 |
boolean contains(Object obj) | 判断集合是否包含指定的元素 |
boolean containsAll(Collection<?> c) | 判断指定集合是否包含集合c的所有元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 返回集合中元素的个数(集合的长度) |
boolean retainAll(Collection<?> c) | 从指定集合中保留包含集合c的元素,其他元素则删除(交集) |
list接口
List相较于Collection的特有方法
方法 | 说明 |
void add(int index,E element) | 在列表的指定位置插入指定元素 |
boolean addAll(int index,Collection<? extends E> c) | 将指定c中的所有元素都插入到列表中的指定位置。 |
int indexOf(Object o) | 返回列表中首次出现指定元素的索引,如果列表不包含此元素,则返回-1 |
int lastIndexOf(Object o) | 返回列表中最后出现指定元素的索引,如果列表不包含此元素,则返回-1 |
E remove(int index) | 删除指定索引处的元素,返回被修改的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 获得指定索引处的元素 |
LinkedList相较于List的特有方法
方法 | 说明 |
void addFirst(E e) | 在列表开头插入指定元素 |
void addLast(E e) | 在列表末尾添加指定元素 |
E getFirst() | 返回此列表的第一个元素 |
E getLast() | 返回此列表的最后一个元素 |
E removeFirst() | 删除并返回列表中的第一个元素 |
E removeLast() | 删除并返回列表中的最后一个元素 |
E pop() | 从此列表所表示的堆栈处弹出顶部元素,等效于removeFirst |
void push(E e) | 将元素推入此列表所表示的堆栈,这个等效于addFirst(E e) |
boolean isEmpty() | 判断列表是否包含元素,如果不包含元素则返回true |
ArrayList与LinkedList的相同与不同点
Vector与ArrayList的相同与不同点
Vector与ArrayList的使用是相同的,二者没有特有的方法
ArrayList是一个可以处理变长数组的类型,可以存放任意类型的对象。ArrayList的所有方法都是默认在单一线程下进行的,因此ArrayList不具有线程安全性。
Vector也是一个类似于ArrayList的可变长度的数组类型,它的内部也是使用数组来存放数据对象的。值得注意的是Vector与ArrayList唯一的区别是,Vector是线程安全的。在扩展容量的时候,Vector是扩展为原来的2倍,而ArrayList是扩展为原来的1.5倍
Stack
Stack栈容器,是Vector的子类,它实现了一个标准的后进先出的栈。
它通过5个操作方法对Vector进行扩展,允许将向量视为堆栈。
方法 | 说明 |
boolean empty() | 测试这个栈是不是空的 |
E peek() | 查看这个栈顶部的对象,并返回这个值 |
E pop() | 删除这个栈顶部的对象,并返回这个值 |
E push(E e) | 添加一个元素,放在这个栈的顶部 |
int search(Object o) | 返回指定对象在栈中的位置(先进的位置靠后,第一个进去的元素,位置是最后的,最后进去的元素,位置是1) |
Stack中的 int search(Object o)方法
Set接口
Set接口及其实现类无新增方法,用Collection中的方法