目录
集合
1、 集合的理解和好处
平时保存多个数据时,我们使用的是数组,而数组在使用的时候有些不足的地方,数组与集合的对比如下:
数组
缺点:
1、长度一旦被制定就固定了,不能动态变化
2、同一数组只能保存一种类型的元素
3、使用数组增删改查操作比较繁琐
集合
优点:
1、可以动态的存放任意数量的元素对象,使用方法简便
2、提供了一系列方便的操作对象的方法,如:add(增加)、remove(删除)、set(设置元素的值)、get(获取)等
2 、集合的框架体系
Java 的集合类很多,主要分为两大类 (单列集合、双列集合):
单列集合体系图:
双列集合(key-value)体系图:
3、 Collection 接口和常用方法
3.1 Collection 接口实现类的特点
Collection接口继承了Iterable接口:
Public interface Collection<E> extends Iterable<E>
1.Collection 的实现子类可以存放多个元素,每个元素都可以是一个Object对象
2.Collection 接口没有直接实现它的子类,是通过它的子接口List和Set来实现的
3.Collection 的实现子类 有些是有序的(List接口下的实现子类),有些是无序的(Set接口下的实现子类)
4.Collection 的实现子类 有些可以存放重复元素(List接口下的实现子类),有些是不可以(Set接口下的实现子类)
3.2 Collection 接口遍历元素的两种方式
1、使用 Iterator(迭代器)
(1)、Iterator 接口称为迭代器,主要用于遍历 Collection 实现子类中的元素
(2)、实现了 Collection 接口的集合类都有一个Iterator() 方法,用以返回一个实现了 Iterator 接口的对象,即返回一个迭代器
(3)、Iterator 仅用于遍历集合中的对象元素,它本身并不存放对象
(3)、Iterator 的执行原理:使用 hasNext() 方法来判断集合是否存在下一个元素,并一个元素一个元素的往下指向(如同一个指针)
例:while( iterator.hasNext() ) {
System.out.println( iterator.next() );
}
2、使用增强 for 循环(foreach循环)进行遍历
说明:增强for循环的实质为简化版的Iterator (迭代器)
4、 List 接口和常用方法
4.1 List 接口基本介绍
1、list接口是collection接口的子接口
2、list集合类中的元素是有序的(即存取顺序一致),并且可以有相同元素对象
3、list集合中的每个元素都有对应的索引值(从0开始顺序编号)
4、实现了list接口的常用类有:ArrayList(基于数组实现,线程不安全)、LinkedList(基于链表实现,线程不安全)、Vector(与ArrayList类似,但是线程安全)三个,其余实现了list接口的类需自行查询对应的JDK API文档
4.2 List 接口的常用方法
增加
add();
addAll(); //把另一个集合中的全部元素增加到指定集合中
删除
remove();
removeAll(); //把另一个集合中与指定集合相同的全部元素从指定集合中删除
指定位置设置指定值(对象)
set(int, Object);
查找集合中对象的索引值
indexOf(Object); //第一次出现的索引
lastIndexOf(Object); //最后一次出现的索引
查找指定索引处的对象
get(int);
清空集合内容
clear();
长度大小
size();
注:具体的方法还是需要查看对应的JDK API文档
4.3 List 接口的三种遍历方式
1、使用 Iterator (迭代器)遍历
2、使用增强for(foreach循环)循环遍历
3.使用普通for循环遍历,即根据索引值进行遍历,对于之后实现了set接口的类不适用
5 、ArrayList 简介
- ArrayList底层里维护了一个Object类型的数组 elementData
- 当创建了ArrayList对象时,如果使用的是无参构造器,则初始化elementData数组的容量为0,添加了10个以内的数据时,elementData数组容量被自动扩容为10,之后每次超过容量,则扩容为当前容量的1.5倍大小
- 如果创建ArrayList对象时,使用的是指定大小的构造器,则初始elementData的容量为指定大小,之后每次超过容量,则扩容为当前容量的1.5倍大小
6、 Vector 简介
- Vector的底层也是一个elementData数组
- 当创建了Vector对象时,如果使用的是无参构造器,则初始化elementData数组的容量为0,添加了10个以内的数据时,elementData数组容量被自动扩容为10,之后每次超过容量,则扩容为当前容量的2倍大小
- 如果创建Vector对象时,使用的是指定大小的构造器,则初始elementData的容量为指定大小,之后每次超过容量,则扩容为当前容量的2倍大小
- Vector的方法是有线程锁(synchronized)限制的
优点:需要进行多线程操作时,具备线程安全
缺点:由于线程锁的存在,运行时相对ArrayList运行速度会慢一些
7、 ArrayList 和 Vector 比较
底层结构 | 线程安全 | 扩容机制 | |
ArrayList | 可变数组 | 不安全,但效率高 | 有参构造:1.5倍 无参构造: 第一次大小为10 第二次开始扩大1.5倍 |
Vector | 可变数组 | 安全,效率不高 | 有参构造:2倍 无参构造: 第一次大小为10 第二次开始扩大2倍 |
8 、LinkedList 简介
总体描述
- LinkedList底层实现了双向链表和双端队列的特点
- 可以添加任意元素(可重复),包括null
- 线程不安全,没有实现线程同步
底层结构
- LinkedList底层为一个双链表,具备first和last两个属性分别只想首节点和尾节点
- 每个节点对象中又有prev、next、item三个属性,分别代表指向该节点的前一个节点,指向该节点的后一个节点,当前节点
优点:增加与删除元素时效率很高,不需要进行数组的拷贝等繁琐的操作
9、 ArrayList 和 LinkedList 比较
底层结构 | 增删效率 | 改查效率 | |
ArrayList | 可变数组 | 较低,原因:数组扩容 | 较高,原因:根据数组索引直接操作 |
LinkedList | 双向链表 | 较高,原因:直接在链表上追加 | 较低,原因:需要遍历链表 |
ArrayList 和 LinkedList的选择
- 当修改与查询操作多时,选择ArrayList
- 当增加与删除操作多时,选择LinkedList
10 、Set 接口和常用方法
1、实现了set接口的类的集合对象可以存放null值,但是不能存放重复的元素
2、实现了set接口的类的集合对象存放的数据是无序的(添加时的顺序与取出时的顺序不同)
3、遍历取出数据顺序是按照一定的算法固定排好序的
4、实现了set接口的类的集合对象存放的数据没有对应的索引值,也就意味着它不能使用普通的for循环(利用索引遍历元素)进行遍历
5、实现了set接口的常用类有:HashSet、TreeSet、LinkedHashSet
6、set接口的常用方法:
增加
add();
addAll();
删除
remove();
removeAll();
清空集合内容
clear();
长度大小
size();
与List的相似,因为它们都是Collection的子接口,但是相比List接口的方法,set接口没有用索引值进行操作的方法,因为它是无序的
10.1 Set 接口实现类-HashSet
基本介绍:
1.HashSet实现了Set接口
2.当创建一个HashSet时,实际上是创建了一个HashMap
3.因为它是实现了Set接口的,所以它也不能存放重复元素,可以存放一个null值
4.存放的数据是无序的(添加时的顺序与取出时的顺序不同)
5.HashSet是由数组+链表+红黑树组成的
扩容机制:
- 添加第一个元素时,存储数据的数组table大小扩容到16,当元素个数达到临界值12(0.75 * 16 = 12)时,大小就扩大2倍变为32,之后以此类推
- 当table中的的其中一条链表的长度超过8时,多一个table就扩大两倍,直到table大小为64后,链表就被优化为了树(红黑树)
10.2 Set 接口实现类
- - LinkedHashSet
- LinkHashSet能够确保元素的插入顺序和取出顺序一致
- LinkHashSet中维护了一个hash表和一个 双向链表(每个节点由pre、value和next三个属性组成,pre指向前一个节点,value存放值,next指向后一个节点,构成一个双向链表)组成
说明:能确保元素的插入顺序和取出顺序一致的原因就在于有双向链表的存在
10.3 Set 接口实现类-TreeSet
1、当使用TreeSet的无参构造器创建TreeSet时,存放的元素仍然是无序的
2、需要使用TreeSet 提供的一个有参构造器,传入一个比较器(Comparator类),并在其中指定排序规则(重写compare方法),进行排序
11、Map 接口和常用方法
基本介绍:
- Map用于存放具有映射关系的数据:key-value
- Map中的key不允许重复,value可以重复,都可以取任意类型的数据,包括null,但是key只能有一个为null
- key与value一一对应(如身份证号与名字一一对应)
- 每一对key-value都会被封装到一个Hash Map$Node节点中
- Map的常用实现类有:HashMap、Hashtable和Properties
常用方法:
- put:添加
- remove:根据键值删除对应关系
- get:根据键值获取value值
- size:获取元素个数
- isEmpty:判断是否为空
- clear:清空
- containKey:查找键值是否存在
- keySet:获取所有的键值
- entrySet:获取所有关系
- values:获取所有value值
11.1Map 接口实现类-HashMap
- HashMap是Map接口实现类中最常用的,以key-value(键值对)形式存放数据
- key不允许重复,value可以重复,都可以取任意类型的数据,包括null,但是key只能有一个为null
- key与value一一对应,每一对key-value都会被封装到一个Hash Map$Node节点中
- 因为底层是按照hash表存储的,所有添加顺序与取出顺序不同
- HashMap没有实现线程同步,线程不安全
11.2Map 接口实现类-Hashtable
- Hashtable以key-value形式存放数据
- 基本使用方法与HashMap基本一致
- key不允许重复,value可以重复,都可以取任意类型的数据,但是都不能为null
- Hashtable实现了线程同步,线程安全
11.3Map 接口实现类-TreeMap
1、TreeMap的使用与TreeSet的类似
2、需要使用TreeMap提供的一个有参构造器,传入一个比较器(Comparator类),并在其中指定排序规则(重写compare方法),进行排序
11.4Map 接口实现类-Properties
- Properties以key-value形式存放数据
- 其使用特点与Hashtable类似
- 主要用于从 xxx.properties 文件中加载数据到Properties类对象中进行读取和修改,用作配置文件
12、总结-开发中如何选择集合实现类
总结:
对集合实现类的选择与使用时,根据不同的业务需求,选择合适的进行使用:
先判断存储的类型(单列集合、双列集合)
单列集合:
允许重复:List接口
增加删除操作多时:LinkList
修改查找操作多时:ArrayList
不允许重复:Set接口
无序:HashSet
根据需要排序:TreeSet
存取顺序一致:LinkedHashSet
双列集合:
键值无序:HashMap
键值需要排序:TreeMap
键值存取顺序一致:LinkedHashMap
读取文件:Properties