Java集合进阶
List系列集合:添加的元素是有序、可重复、有索引
Set系列集合:添加的元素是无序、不重复、无索引
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() | 返回集合中元素的个数/集合的长度 |
迭代器遍历
迭代器在Java中的类是Iterator,迭代器是集合专用的遍历方式
Collection集合获取迭代器
方法名称 | 说明 |
---|---|
Iterator<E> iterator() | 返回迭代器对象,默认指向当前集合的0索引 |
Iterator中的常用方法
方法名称 | 说明 |
---|---|
boolean hasNext() | 判断当前位置是否有元素,有元素返回true,没有元素返回false |
E next() | 获取当前位置的元素,并将迭代器对象移向下一个位置 |
细节注意点:
-
如果当前位置没有元素,还要强行获取,会报错NoSuchElementException
-
迭代器遍历完毕,指针不会复位
-
循环中只能用一次next方法
-
迭代器遍历时,不能用集合的方法进行增加或者删除,可以使用迭代器提供的remove方法进行删除
增强for遍历
增钱for的底层就是迭代器,为了简化迭代器的代码书写的。所有的单列集合和数组才能用增强for进行遍历
格式:
for (元素的数据类型 变量名:数据或者集合){
}
Lambda表达式遍历
方法名称 | 说明 |
---|---|
default void forEach(Consumer<? Super T> action): | 结合lambda遍历集合 |
List集合
Collection的方法list都继承了,List集合因为有索引,所以多了很多索引操作的方法
方法名称 | 说明 |
---|---|
void add(int index , E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index , E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
List集合的遍历方式
-
迭代器遍历:在遍历的过程中需要删除元素
-
列表迭代器:在遍历的过程中需要添加元素
-
增强for遍历、Lambda表达式:仅仅想遍历
-
普通for循环:想在遍历的时候操作索引
LinkedList集合
特有方法 | 说明 |
---|---|
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 在指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
泛型
泛型是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:<数据类型> 泛型只能支持引用数据类型
泛型的好处
-
统一数据类型
-
把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来
泛型的细节
-
泛型中不能写基本数据类型
-
指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
-
如果不写泛型,类型默认是Object
泛型类
当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
格式: 举例:
修饰符 class 类名<类型>{ public class ArrayList<E>{
} }
此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成:T、E、K、V等
泛型接口
格式: 举例:
修饰符 interface 接口名<类型> { public interface List<E>{
} }
泛型的继承和通配符
泛型不具备继承性,但是数据具备继承性
二叉树
二叉查找树
前序遍历:中间结点,左子结点,右子结点
中序遍历:左子结点,中间结点,右子结点
后序遍历:左子结点,右子结点,中间结点
层序遍历:从根结点开始一层一层的遍历
平衡二叉树
规则:任意节点左右子树高度差不超过1
红黑树
是一个二叉查找树,但是不是高度平衡的
红黑树规则:
-
每一个节点或是红色的,或者是黑色的
-
根节点必须是黑色
-
如果一个节点没有子结点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
-
如果某一个节点是红色,那么它的子结点必须是黑色(不能出现两个红色节点相连的情况)
-
对每一个节点,从该节点到其所有后代节点的简单路径上,均包含相同数目的黑色节点
Set系列集合
HashSet底层原理
当链表长度超过8,而且数组长度大于等于64时,自动转换为红黑树;如果集合中存储的是自定义对象,必须要重写hashCode和equals方法。
LinkedHashSet底层原理
底层数据结构依然是哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。
如果要数据去重,默认选择HashSet,如果要求去重且存取有序,才使用LinkedHashSet
TreeSet
默认按照从小到大的顺序排序。TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好。
TreeSet的两种比较方式:
-
默认排序/自然排序:javabean类实现Comparable接口指定比较规则
-
比较器排序:创建TreeSet对象时,传递比较器Comparator指定规则
总结
-
如果想要集合中的元素可重复 -- 用ArrayList集合,基于数组的。
-
如果想要集合中的元素可重复,而且当前的增删操作明显多于查询 -- 用LinkedList集合,基于链表的。
-
如果想对集合中的元素去重 -- 用HasnSet集合,基于哈希表的。
-
如果想对集合中的元素去重,而且保证存取顺序 -- 用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet。
-
如果想对集合中的元素进行排序 -- 用TreeSet集合,基于红黑树。后续也可以用List集合实现排序。