一、总体介绍
二、Collection
1. 单列集合体系结构
- List系列集合: 添加的元素是有序、可重复、有索引
- Set系列集合: 添加的元素是无序、不重复、无索引
- 有序:(输入与输出顺序相同)
2. Collection功能
| 方法名称 | 说明 |
|---|---|
| public boolean add(E e) | 把给定的对象添加到当前集合中 |
| public void clear() | 清空集合中所有的元素 |
| public boolean remove(E e) | 把给定的对象在当前集合中删除 |
| public boolean contains(object) | 判断当前集合中是否包含给定的对象 |
| public boolean isEmpty() | 判断当前集合是否为空 |
| public int size() | 返回集合中元素的个数/集合的长度 |
- 如果存的是自定义对象,没有重写equals方法,那么就默认使用Object类中的equals方法进行判断,而Object类中equals方法,依赖地址值进行判断。所以需要在自定义的JavaBean类中,重写equals方法。
3. Collection的遍历方式
迭代器遍历、增强for遍历、Lambda表达式遍历
3.1 迭代器遍历
-
迭代器在Java中的类是Iterator,是集合专用的遍历方式。
-
Collection集合获取迭代器的方法:
Iteator<E> iterator()返回迭代器对象,默认指向当前集合的0索引。 -
迭代器遍历集合的时候是不依赖索引的
-
迭代器遍历完毕,指针不会复位
-
迭代器遍历时,不能使用集合的方法进行增加或者删除。删除可以使用remove,但是不能增加。
-
常用方法:
| 方法名称 | 说明 |
|---|---|
| boolean hasNext() | 判断当前位置是否有元素,有元素返回true,没有元素返回false |
| E next() | 获取当前位置的元素,并将迭代器对象移向下一个位置。 |
Collection<String> coll=new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
/* 迭代器遍历
*快捷方式: main直接输出 public static void main
*sou 直接输出 System.out.println
*command d 复制选中行 */
//1. 创建指针
Iterator<String> it=coll.iterator();
while(it.hasNext()) //2. 判断是否有元素
{
String str=it.next(); //3. 获取元素,移动指针
System.out.println(str);
}
3.2 增强for遍历
-
增强for的底层就是迭代器,为了简化迭代器的代码书写的。
-
所有的单列集合和数组才能使用增强for进行遍历。
-
修改增强for中的变量,不会修改集合中原本的数据。
coll.add("111");
coll.add("222");
coll.add("333");
/*
* 增强for循环
* 快捷生成方法:集合名字+for 回车
* */
for(String s:coll)
{
s=“4";
System.out.println(s); // 111 222 333
}
3.3 lambda表达式遍历
- 利用匿名内部类方式的底层原理:自己遍历集合,依次得到每一个元素,把得到的每一个元素,传递给下面的accept方法,s依次表示集合中的每一个元素。
/*使用匿名内部类方法进行遍历*/
Collection<String> coll=new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
/* coll.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
//lambda 表达式
coll.forEach(s-> System.out.println(s));
3.4 总结
- Collection是单列集合的顶层接口,所有方法被List哥Set系列集合共享。
- 常见的成员方法:add、clear、remove、contains、isEmpty、size。
- 遍历过程中要删除元素用迭代器,仅仅遍历用增强for或者Lambda。
4. List集合的特有方法
- Collection的方法List都继承了。
- List集合因为有索引,所以多了很多索引操作的方法。
- 使用add方法在指定位置插入元素时,原来索引上的元素会依次往后移。
- List<Integer> 删除时,优先调用实参和形参一致的方法。
| 方法名称 | 说明 |
|---|---|
| void add(int index,E element | 在此集合中的指定位置插入指定的元素 |
| E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
| E set(int index ,E element) | 修改指定索引处的元素,返回被修改的元素 |
| E get(int index) | 返回指定索引处的元素 |
List<String> list=new ArrayList<>();
list.add(0,"aaa");
list.add(1,"bbb");
list.add("ccc");
System.out.println(list);
String s=list.remove(0);
System.out.println(s);
System.out.println(list);
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//优先使用int基本类型的remove函数,删除指定索引处
list.remove(1);
System.out.println(list); //1,3
//手动装箱,删除对象
Integer i= Integer.valueOf(3);//1
list.remove(i);
System.out.println(list);
4.1 List集合的遍历方式
迭代器遍历(删除)、列表迭代器遍历(添加)、增强for遍历,Lambda表达式遍历(仅遍历)、普通for循环(因为list集合存在索引)(遍历时想操作索引)
5. ArrayList集合底层原理
对于jdk8
- 利用空参创建的集合,在底层默认创建一个长度为0的数组
- 添加第一个元素时,底层会创建一个新的长度为10的数组
- 存满时,会扩容1.5倍
- 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准
6. LinkedList集合
底层数据是双链表,查询慢,首尾操作的速度是非常快的,所以多了很多首尾操作的特有API。
| 特有方法 | 说明 |
|---|---|
| public void addFirst(E e) | 在该列表开头插入指定的元素 |
| public E getFirst() | 返回此列表中的第一个元素 |
| public E getLast() | 返回此列表中的最后一个元素 |
| public E removeFirst() | 从此列表中删除并返回第一个元素 |
| public E removeLast() | 从此列表中删除并返回最后一个元素 |
7. 泛型
- 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
- 泛型只能支持引用数据类型。(因为Object类不是基本类型的父类或者基类)
- 泛型把运行时期的问题提到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
- 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型。
- 如果不写泛型,默认类型是Object。
- 泛型类
public class ClassName<E> {} - 泛型方法
public static <E> void MethodName() - 泛型接口
public interface InterfaceName<E>{}
7.1 泛型类
- 当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类。
7.2 泛型方法
方法中形参类型不确定时:
- 使用类名后面定义的泛型 (所有方法都能用)
- 在方法申明上定义自己的泛型 (只有本方法能用)
7.3 泛型接口
如何使用一个带泛型的接口:
- 实现类给出具体类型
- 实现类延续泛型,创建对象时再确定。
7.4 泛型的继承和通配符
- 泛型不具备继承性,但是数据具备继承性
- 对不确定类型进行限定的方法
8. Set
无序、不重复、无索引
- HashSet: 无序、不重复、无索引
- LinkedHashSet: 有序、不重复、无索引
- TreeSet:可排序、不重复、无索引 Set接口中的方法上基本上与Collection的API一致。
8.1 HashSet
- HashSet集合底层采取哈希表存储数据
- 哈希表是一种对于增删改查数据性能都较好的结构
- JDK8之前:数组 + 链表 ;JDK8开始:数组 + 链表 + 红黑树 (当链表长度超过8,数组长度大于等于64时,链表自动转换为红黑树 )
- 如果集合中存储的是自定义对象,必须要重写hashCode和equals方法
- HashSet去重原理:首先使用HashCode方法,接着使用equals方法
哈希值
- 根据hashCode方法算出来的int类型的整数
- 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
- 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值
对象的哈希值特点
- 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
- 如果已经重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
- 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
HashSet底层原理
- 创建一个默认长度16,默认加载因子为0.75的数组,数组名table
- 根据元素的哈希值跟数组的长度计算出应存入的位置
- 判断当前位置是否为null,如果是null直接存入
- 如果不为null,表示有元素,则调用equals方法比较属性值
- 一样:不存 不一样:存入数组,形成链表
JDK8以前:新元素存入数组,老元素挂在新元素下面
JDK8以后:新元素直接挂在老元素下面
8.2 LinkedHashSet
有序(存取顺序一致)、不重复、无索引。
- 原理:底层数据结构依然是哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序
8.3 TreeSet
不重复、无索引、可排序。
- 可排序:按照元素的默认规则(由小到大)排序。
- TreeSet底层基于红黑树的数据结构实现排序的,增删改查性能都比较好。
- 对于数值类型:Integer、Double,默认按照从小到大的顺序进行排序。
- 对于字符、字符串类型:按照字符在ascii码表中的数字升序进行排序。
两种比较方式
- 默认排序:JavaBean类实现Comparable接口指定比较规则
- 比较器排序:创建TreeSet对象时候,传递比较器Comparator指定规则。
- 使用原则:默认使用第一种,第一种不满足需求时,使用第二种
8.4 使用技巧
- 如果想要集合中的元素可重复: 使用ArrayList集合,基于数组的。
- 如果想要集合中的元素可重复,而且当前的增删操作明显多于查询: 使用LinkedList集合,基于链表的。
- 如果想要对集合中的元素去重: 用HashSet集合,基于哈希表的。
- 如果想对集合中的元素去重,而且保证存取有序: 使用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet
- 如果想对集合中的元素进行排序: 使用TreeSet集合,基于红黑树。后续也可以用List集合实现排序。
三、Map
1. 双列集合体系结构
- 双列集合一次需要存一对数据,分别为键和值
- 键不能重复,值可以重复
- 键和值是一一对应的,每一个键只能找到自己对应的值
- 键+值这个整体,称为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”
2. Map的常见API
Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的
| 方法名称 | 说明 |
|---|---|
| V put (K key,V value) | 添加元素 |
| V remove (Object key) | 根据键删除键值对元素 |
| void clear () | 移除所有的键值对元素 |
| boolean containKey (Object key) | 判断集合是否包含指定的键 |
| boolean containsValue (Object value) | 判断集合是否包含指定的值 |
| boolean isEmpty () | 判断集合是否为空 |
| int size () | 集合的长度,也就是集合中键值对的个数 |
- put添加数据时,如果键不存在,则返回null。如果存在,返回被覆盖的值。
3. Map的遍历方式
键找值、键值对、Lambda表达式。
3.1 键找值
3.2 键值对
3.3 Lambda表达式
4. HashMap
- HashMap是Map里面的一个实现类
- 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
- 特点都是由键决定的:无序、不重复、无索引
- HashMap和HashSet底层原理是一模一样的,都是哈希表结构
- 依赖hashCode和equals方法保证键的唯一
- 如果键存储的是自定义对象,需要重写hashCode和equals方法;如果是值,则不用
5. LinkedHashMap
- 由键决定:有序(存取一致)、不重复、无索引
- 原理:底层的数据结构依然是哈希表,只是每个键值对元素又额外的多了一个双链表的机制存储顺序
6. TreeMap
- TreeMap和TreeSet底层原理一样,都是红黑树结构的。
- 由键决定特性:不重复、无索引、可排序。
- 可排序:可以对键进行排序
- 注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
代码书写两种排序规则
- 实现comparable接口,指定比较规则。
- 创建集合时传递Comparator比较器对象,指定比较规则。