第十三章 集合
1.集合体系图
上面这个例子每次放单列数据的称为单例集合,下面放双列数据的称为双列集合
2.Collection
1.Collection方法
有序的是指存放和取出的次序是一致的
add 添加单个元素
这里使用list来接收,相当于向上转型
此时List中装的不是基本数据类型,而是一个对象
其中的add(10)相当于add(new.Integer(10))
remove 删除指定元素
contain 查找元素是否存在
size 获取元素个数
isEmpty 判断是否为空
clear 清空
addAll 添加多个元素
containsAll 查找多个元素是否都存在
removeAll 删除多个元素
2.Collection集合遍历方式1(Iterator迭代器遍历)
返回下一个元素类型Object的原因是不管什么元素,它都可以接收
3.Collection集合遍历方式2(增强for循环)
4.测试题
3.List(有序,可重复)
1.List接口方法
add添加单个元素
如果前面没有带位置,默认是加在最后的
addAll添加多个元素
get获取指定位置元素
indexOf返回元素在集合中首次出现的位置
LastIndexOf返回元素在集合中最后一次出现的位置
显示的是最后一次出现韩顺平的位置
remove删除元素
set替换指定位置元素
subList返回子集合
2.List接口练习
3.List三种遍历方式
使用List接口的其他子类,例如Vector,LinkedList可以得到一样的结果
4.List排序练习
4.ArrayList
1.ArrayList注意事项
2.ArrayList扩容机制
(1)
Object数组意味着什么数据都可以往里面放
(2)
(3)
如果开始的指定大小为8,则
3.ArrayList底层源码1
oldCapacity >> 1 ,右移运算符 ,原来长度的一半 再加上原长度也就是每次扩容是原来的1.5倍;
下面这个源码是jdk1.8的版本
4.ArrayList底层源码2
5.Vector
1.vector注意事项
(2)
2.Vector源码解读(ArrayList与Vecotr的比较)
capacityIncrement为0,所以每次都是两个oldCapacity相加
如果是有参构造,则(其他的业务逻辑一样)
6.LinkedList
1.LinkedList底层源码解读(双向列表模拟)
2.LinkedList源码图解
增加节点的源码
删除节点的源码
修改某个节点对象
得到某个节点对象
遍历
7.List集合选择(ArrayList与LinkedList如何选择)
8.set接口方法(无序,不可重复)
增加add
他是固定的
取10次发现取出的顺序的一样的
普通for循环就用不了了,虽然可以通过set.size()得到set的大小,但没有提供get方法
删除remove
9.HashSet
1.HashSet全面说明
下面重新new HashSet()赋予set,则set此时为空
上面看源码解读3即可得知为什么
2.数组链表模拟
3.HashSet扩容机制
应该是达到8个
4.HashSet源码解读1
增加第一个元素“java”
这里的PRESENT起到占位作用
此时第一个元素java就加入其中,下面的else部分不会执行,此时执行以下部分
5.HashSet源码解读2
添加第二个元素“php”
第三次,写一个相同的“java”,观察不添加的情况
第二次输入的“java”跟第一个一样同样进入位置3,所以下面不是为null,
所以要执行下面的else部分
6.HashSet源码解读3
这里的equals方法是由程序员重写来确定的,左上角的“java”“php”都是String类型,equals()是开发者定义好的比较内容是否一样。
下面这里为了保证所有的内容放到一条链上,重写了hashCode()方法
上面这个到8之后本来应该树化,但数组长度还没有到64,所以先延长数组长度到32
下面再添加一次,仍然会触发树化机制,但由于没有到64,所以还是先先延长数组长度到64
延长数组之后,所有的内容全移到36这个位置上面,一共10个
再添加第11个的时候就会转成一个树
7.HashSet源码解读4
这里的扩容不是table表本身超过12个才会增加,而是里面的内容只要超过12个就会扩容,下面的例子中我们在一条链上放了7个A对象,另一条链上放了7个B对象,此时table也会扩容。
下面先在索引为4的链表中放了7个,再在索引为8的链表中放入,当超过12个的时候,
table进行扩容
8.HashSet最佳实践
此时三个不同的对象
为了满足题目的要求,我们要重写equals方法
这里是选择模板,直接next
上面在添加第三个的时候,我们先计算hashCode,发现与第一个一样,但是hashCode值一样不一定就加不进去,下面还要继续看值是否相同。当hashCode相同,内容不同的时候,我们就将内容挂在链表的后面
9.HashSet思考题
10.LinkedHashSet
1.LinkedHashSet介绍
(2)原先的HashSet的底层HashMap维护的是一个数组+单向链表
(3)我们使用LinkedHashMap的时候,我们的取出顺序与插入顺序的一致的
下图体现了我们在取LinkedHashSet的值的时候是有序的
2.LinkedHashSet源码解读
下图我们发现LinkedHashSet的底层是LinkedHashMap
第二个“456”是加不进去的
下面是最后的结果
3.LinkedHashSet课堂练习
上图中显示在默认机制下,所有的内容都可以添加成功
下面重写方法进行处理
下面如果只重写hashCode()方法,那么也可以加进去
11.Map
1.Map接口特点1
(1)我们之前将set的时候,只放了一个Key进去,而value是系统给的一个对象常量PRESENT
这里不用add进行添加,而是使用put
我们发现取出的内容是无序的,因为是根据hashCode值进行存储的
(2)
(3)
Key不允许重复
当key相同,value不同时,新的value会替换旧的value
(4)
value可以重复
(5)
Key不可以重复,所以只能有一个null
下面这种情况就会发生value的替换
下面这种情况即key不同,value是两个null,可以存在
(6)
大部分情况下我们选用String类型来作为key,但实际情况下可以是Object类型的
我们甚至可以直接new一个Object类作为key
(7)
2.Map接口特点2
Map真正的结构就是左边有个table表,这个table表中是以数组+链表+红黑树的方式来组织我们的node,但是为了方便管理,在底层做了一个控制,将每一个node封装成一个entry,然后再将entry放到一个叫entrySet的集合中,除此之外,还提供了一个叫keyset()的方法,将我们key中的对象封装一个叫set的集合中(这里并不是真的将key装在set中,只是一个指向),也就是说可以单独的取出key对象,
==================================================================================================================================================
就是先将HashMapNode中key,value转成entry,再将其转成entrySet
下面的指向上面的地址
3.Map接口方法
4.Map六大遍历方式
第一组方法:通过KeySet
第二组方法:通过values
下面这种方法只能取value,不能取key
这里的values没有提供get方法,所以不能使用普通for循环
第三组方式: 通过entrySet来获取
接着进行向下转型,本身应该转为HashMap$Node,但是由于没有提供相应的方法,所以这里转成Map.Entry
5.Map课堂练习