刨析源码,深层讲解 Java-集合框架( 四 )


第一次调用add()时,底层才创建了长度10的数组,并将数据123添加[0]
list.add(123);
后续的添加和扩容操作与jdk7相同 。
结论:jdk7中的的对象的创建类似于单例的饿汉式,而jdk8中的的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存 。
3.4 List实现类之二:
3.4.1 概述
? 对于频繁的插入、删除操作,使用此类效率比高;
? 底层使用双向链表存储 。
? :双向链表,内部没有声明数组,而是定义了Node类型的first和last,
用于记录首末元素 。同时,定义内部类Node,作为中保存数据的基本结构 。
? Node除了保存数据,还定义了两个变量:
prev变量记录前一个元素的位置
next变量记录下一个元素的位置
3.4.2 源码分析
LinkedList list = new LinkedList(); //内部声明了Node类型的first和last属性,默认值为nulllist.add(123);//将123封装到Node中,创建了Node对象 。//Node定义为:(体现了LinkedList的双向链表的说法)private static class Node {E item;Node next;Node prev;Node(Node prev, E element, Node next) {this.item = element;this.next = next;this.prev = prev;}}
3.5 List实现类之三: 3.5.1 概述
? 作为List接口的古老实现类 。
? 线程安全的,效率低 。
? 底层使用[] 存储 。
?在各种list中,最好把作为缺省选择 。当插入、删除频繁时,使用;总是比慢,所以尽量避免使用 。
?新增方法:
方法
void ( obj)
void ( obj,int index)
void ( obj,int index)
void ( obj)
void ()
3.5.2 源码分析
jdk7和jdk8中通过()构造器创建对象时,底层都创建了长度为10的数组 。在扩容方面,默认扩容为原来的数组长度的2倍 。
3.6 、、三者的异同?
? 同:
① 三个类都是实现了List接口 。
② 存储数据的特点相同:存储有序的、可重复的数据 。
? 不同:见上
4. 子接口之二:Set接口 4.1 概述
? Set接口是的子接口,set接口没有提供额外的方法 。
? 存储无序的、不可重复的数据 。Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败 。
? Set 判断两个对象是否相同不是使用 == 运算符,而是根据 () 方法 。
? 要求:
向Set(主要指:、)中添加的数据,其所在的类一定要重写()和(),且重写的()和()尽可能保持一致性:相等的对象必须具有相等的散列码 。
重写两个方法的小技巧:对象中用作 () 方法比较的 Field,都应该用来计算值 。
? 重写 () 方法的基本原则
? 重写 () 方法的基本原则
以自定义的类为例,何时需要重写()?
当一个类有自己特有的“逻辑相等”概念,当改写()的时候,总是要改写(),根据一个类的()方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据.()方法,它们仅仅是两个对象 。
因此,违反了“相等的对象必须具有相等的散列码” 。
结论:重写方法的时候一般都需要同时复写方法 。通常参与计算的对象的属性也应该参与到()中进行计算 。
4.2 Set实现类之一: 4.2.1 概述
存储无序的、不可重复的数据 。
4.2.2 添加元素的过程
我们向中添加元素a,首先调用元素a所在类的()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:
如果此位置上没有其他元素,则元素a添加成功 。—>情况1如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值: