Java-集合
1 概念
Java集合是使程序能够存储和操作元素不固定的一组数据,所有Java集合类都位于java.util包中
数组和集合对比:
数组 | 集合 |
---|---|
长度固定 | 长度不固定 |
存放任意类型 | 不能存放基本数据类型,只能存放对象的引用 |
注意: 如果集合中存放基本数据类型,一定要将其"装箱"成对应的"基本数据类型包装类".
2 继承体系
Java中的集合类主要由连个接口派生而出:Collection和Map.Collection和Map是Java结合框架的根接口,这两个接口又包含了一些子接口和实现类
由以上两图我们可以看出Java集合类有清晰的继承关系,有很多子接口和实现类。但是,并不是所有子接口或实现类都是最常用的。
下面我们列举出最常用的几个子接口和实现类:
Collection ——> List ——> ArrayList类
Collection ——> List ——> LinkedList类
Collection ——> Set ——> HashSet类
Collection ——> Set ——> SortedSet接口 ——> TreeSet类
Map ——> HashMap类
Map ——> SortedMap ——> TreeMap类
3 Collection
Collection接口是List接口和Set接口的父接口,它定义的方法可以用于操作List集合和Set集合。
Collection接口定义的方法:
4 Iterator(迭代器)
迭代器是一种模式,又称光标,它可以使对于序列类型的数据结构的遍历行为和被遍历的对象分离
我们不需要关心该序列底层数据结构是什么样子的,只要拿到这个对象,使用迭代器就可以进行遍历这集合对象
4.1 迭代器生成
Iterator it = 集合对象.iterator();
4.2 迭代器的三个方法
1 boolean hasnext();判断光标的下一位是否还有元素,有就是true,没有就是false
2 E next();将迭代器的光标向下移动一位,并取出该元素Element
3 remove();删除当前指向的元素
4.3 注意
迭代器一旦创建,就不能进行添加和删除操作,如果添加或者删除了,必须重新生成迭代器
增强for循环:foreach就是为了让iterator循环访问的形式简单,写起来方便,但是也是不能进行添加和删除操作的
使用普通的for和while循环是可以进行添加和删除的,这种遍历还是和数据结构存储相关的
5 注意
使用contains和remove的时候 如果是自定义类型,需要根据需求覆写equals方法
因为这两个方法底层都会去自动调用对象的 equals方法来进行对象的比较
6 List
6.1 特性
有序,可重复
有指定下标,添加顺序和取出顺序一致
ArrayList : 底层是个Object[] 数组,随机查询效率高,随机删除效率低,默认初始化时10,扩大之后是原来的1.5倍,并且是第一次添加数据的时候进行默认长度设置,只new的时候,不添加数据,则长度为0, 等于是 Object[] elementData= {}; 长度为0
LinkedList : 底层是双向链表,随机查询效率低,随机删除效率高
Vector : 已经过时,属于线程安全,而ArrayList是Vector的升级版 , 默认初始化是10,扩大之后是原来的2倍
6.2 ArrayList
6.3 LinkedList
队列:先到先得
栈:先进后出
链表:链表中保存节点,而一个节点有三部分: 1 添加的数据 2 上一个节点 3 下一个节点
链表是没有下标的,只能从头一个一个找,所有查找较慢
由于链表中都是引用指向,所有删除快,比如三个元素分别是1,2,3 要删除2,只需要1的下一个节点=3的引用,3的上一个节点=1的引用
LinkedList是模拟的双向链表,就是1可以找到2,2也可以找到1
添加指定位置/获取指定位置的值:可以传入索引,但是其实不是下标,而是LinkedList封装的方法,帮助我们自动循环去找
本质上还是循环,因为链表是非连续的空间,只能从头开始一个一个找
只不过LinkedList模拟了下标访问的方式,对我们使用起来提供了便利
6.4 底层实现
6.4.1 节点类
6.4.2 添加
6.4.3 get
7 Set
7.1 概述
无序不可重复
TreeSet : 底层是红黑树(保证元素按照某种顺序排序)
HashSet : 底层是散列
7.2 TreeSet
7.2.1 概述
java.util.SortedSet
java.util.TreeSet:会按照某种顺序进行排序
数字:从小到大
字符串:每位的ASCII
日期:自然日期
比较器有两种
要添加的元素实现比较器
专门准备的一个比较器类(优先级高)
进行排序的时候,根据比较器方法返回的值进行比较
如果是0,说明重复,不添加,如果大于0的,说明元素大,往后放
如果是小于0的,说明要添加的元素小,往前放
7.2.2 基本使用
7.2.3 注意
如果要使用treeSet 那么 元素必须有比较器,两种都可以
否则就会有类型转换异常
1 要添加的原始 实现java.lang.Comparable接口,并实现compareTo方法
2 要写一个比较器类,实现java.util.Comparator比较器接口
很多常用的类都实现了Comparable接口并实现compareTo方法
比如:Integer,String,Date等
所以我们自定义类型的时候,一定要弄比较器类
7.3 比较器
可以让集合中的元素按照某个规则进行排序
在源码中体现了,先判断是否有compare() 如果没有再判断是否有compareTo()
所以 Comparator优先级要高于Comparable
7.3.1 Comparable
也可以叫元素自身比较器,就是要添加的元素需要实现这个接口,一般在我们的自定义类中常用
因为这种方式,直接让要添加的元素类实现接口就可以,编码方便,而Comparator需要单独写比较器类
因为它优先级低,我们给出的排序规则,如果不满足调用处,它还可以根据Comparator进行排序扩展
此时当调用处进行排序扩展的时候,此时Comparator和Comparable同时存在,则Comparator优先级高,所以最终排序规则会按照调用处指定的规则进行排序
7.3.2 Comparator
1 该类有排序(比如Integer实现了Comparable,并且是升序),但是排序规则不是我们想要的,这个时候需要使用Comparator来进行调整排序,因为优先级高
2 如果该类没有排序(没有实现Comparable接口),该类也不是我们写的,如果此时需要排序,则需要使用Comparator来完成
7.4 List排序
所以 如果保存我们自定义类型,想要排序,必须有一个比较器类
根据需求决定用哪一种即可
7.5 HashSet
所以 HashSet 其实就是HashMap,只不过在set中,把map的value部分给屏蔽了
只对外提供key的操作
8 Map
8.1 概述
Hash算法 : 是一种安全的加密算法,把不定长的输入变成定长输出,并不能保证其唯一性
同一个对象生成多次hash值,一定是相同的值,不同对象有可能生成相同的hash值
算法 :
直接寻址法、数字分析法、除留余数法、平方取中法
在java中 把散列表封装到了HashMap和HashTable中,并且HashTable已经过时
Hash算法,在java中就是指hashCode方法
8.2 底层实现
map特性 无序 , key不可重复,value可重复 , 保存键值队映射关系,通过key就可以找到对应的value(比如 橘子 买了4斤 )
map数据结构,数组中保存链表,链表是个单向链表( 值(Entry对象) , 下一个节点 , hash值)
既然是键值对,那么 这个映射关系由谁来维护呢? Map.Entry
本质 就是 Node<K,V>[];
添加过程 :
先使用要存储的映射关系的key对象调用key对象的hashCode方法,生成hash值,然后通过hash算法进行hash,得到数组下标
判断该下标上是否有元素,没有就创建一个Node对象,把hash,key,value存储,并且next是null,把该Node对象保存到数组对应的下标上
如果该数组位上有节点对象,此时调用当前要添加的映射关系的key的equals方法,和当前数组位上所有 节点对象的key进行比较(比较key的equals和hash)
如果有相等的,就用要添加的键值对的value值替换原来的键值对中的value值,并且key既然重复,不添加
如果没有相等的,就把该键值对封装Node对象,并保存到该数组对应的链表中的尾部,原来的尾部节点对象中的next 保存添加的这个新的Node对象
1.8开始,为了左右平衡,查询效率高,又引入了树
并且在添加中会进行判断,如果数组为中的Node个数 大于等于7 就把该数组位中的所有节点都转换TreeNode,以树状存储
HashMap 默认初始化容量是16,并且默认加载因子是0.75
8.3 底层实现
8.4 常用方法
8.5 Map遍历
Map不能直接遍历,需要先转换为集合,然后再使用get方法,获取value
8.6 Properties
9 Map转List并以value排序
1 map 存储键值对而list存储单个元素,第一个问题 就得先把键值对转换为一个单一元素对象(Entry)
通过map.entrySet() 得到set
2 把多个entry封装到list中
ArrayList的构造方法把set传入,或者调用add
3 对list中元素进行排序
Comparator
10 泛型
10.1 概述
类型检查,编译过程中检查类型是否匹配
泛型是在编译阶段对数据的类型进行匹配
优点:统一了数据类型,减少强制类型转换
缺点:只能存储单一类型的数据
结合我们的需求情况,大部分情况都需要保存单一数据类型的数据,所以大部分情况下使用泛型要好很多
泛型只能是引用类型,不能是基本类型
10.2 基本使用
10.3 自定义泛型
泛型本质就是一个占位符,由调用出对这个占位符赋值
如果不赋值默认是Object
常见的占位符:
? | 表示不确定的类型 |
---|---|
T | 表示一个具体的Java类型Type |
K | 表示key,Java中的键值对 |
V | 表示value |
E | 表示Element元素,集合中的数据我们叫元素 |
用什么字母都是可以的,一般是大写,只是占位符而已
语法:public class Linked