集合框架

167 阅读7分钟

java集合框架

Collection接口:单列集合

→list接口:有序,可重复

→实现类:ArraysList,Linkedlist,Vector

→set接口:无序,不可重复

→实现类:Hashset,linkedHashset,Treeset

list接口

面试题:Arraylist,linkedList.Vector三者的异同?

同:三个类都实现了List接口,存储数据的特点相同

不同:

ArrayList:作为list的主要实现类,执行效率高,线程不安全,底层使用Object[]存储

LinkedList:对于频繁增加删除操作效率高,底层使用双向链表存储

Vector:作为list接口的古老实现类,线程安全的,效率低,底层使用Object[]存储

ArraysList底层实现原理:

jdk7:

底层使用Object数组存储,

ArrayList list = new ArrayList();默认初始化长度为10的elementData数组,

list.add(123);//elementData[0]=new Integer(123);

....

list.add(11)//当添加到11位时候,则扩容,默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。

结论:建议开发中使用带参的构造器指定容量,这样能提高效率

jdk8:

总结:ArrayList list = new ArrayList();默认初始化长度为0的elementData数组,在调用add()方法的时候才创建长度为10,这样的好处可以节省内存。其他与jdk7相同。

小结:7的创建类似于单例的饿汉式,8的创建类似于单例的懒汉式。

LikedList底层原理分析:

LikedList llist = new LikedList():内部声明了Node类型的first和last属性,默认值为null

list.add(123)://将123封装到node中,创建了node对象

其中,node定义为:体现了双向链表的说法

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;

}

}

voctor底层源码分析:

扩容是两倍

list常用方法及遍历总结:

  1. List接口中带索引的方法【特有】
  2. public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上
  3. public E get(int index): 返回集合中指定位置的元素
  4. public E remove(int index): 移除列表中指定位置的元素,返回的是被移除的元素
  5. public E set(int index, E element): 用指定元素替换集合中指定位置的元素,返回值是更新前的元素

set接口

set没有自己特定的方法都是跟collection接口中的方法一样

实现类:

HashSet:作为set接口主要实现类,线程不安全的,可以存储null

→LinkedHashSet:作为Hashset子类,遍历其内部数据时可以按照添加的顺序遍历

TreeSet:可以按照添加对象的指定属性,进行排序。底层采用红黑树。添加的内容只能是一种类型,就是要么都放int,要么都放string不能多个。

重点:

一如何理解不可重复性和无序性

1不可重复性

保证添加的元素按照equals()判断时,不能返回true,即相同的元素只能有一个

2无序性

不等于随机性,跟插入顺序无关,而是根据数据的哈希值决定的。

LinkedHashSet使用分析

LinkedHashSet作为hashset的紫烈,在添加数据的同时,每个数据还维护了两个引用,记录次数据前一个数据和后一个数据

优点:对于频繁的遍历操作,LinkedHashset效率高于Hashset

TreeSet说明

特点:底层采用红黑树,查询效率比list高”

排序方式

两种:

1自然排序

实现:实现Compareble,重写Compareto方法指定什么排序,例如String就是重写了这个方法

定义:比较两个对象是否相同的标准为:compareTo()返回0,不再是equals()/

2定制排序

实现:实现Comparetor接口,重写Compare(Object o1,Object o2)定制排序

定义:比较两个对象是否相同的标准为:comparre()返回0,不再是equals()

Map接口

Map接口:双列集合,用来存储一组键值对(key,value)映射关系

键:无序,不可重复的,使用Set存储

值:无序,可重复,使用Collection存储

一个键值对构成一个Entry对象

Map中的entry:无序的,不可重复的,使用set存储

→实现类:

HashMap:作为map的主要实现类,线程不安全,效率高;可以存储null的key和value

→,LikedHashmap,保证在遍历map元素时,可以按照添加的顺序实现遍历。

原因:在原有的hashmap底层结构基础上,添加了一对指针,指向前一个和后一个元素

对于频繁的遍历操作,次 类执行效率高于Hashmap

,Hashtable,:线程安全,效率低不能存储null的key和value

→Properties:常用来处理配置文件,例如jdbc的数据里连接文件

TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序,底层使用红黑树

HashMap的底层:

jdk7:数组+链表

HashMap map =new HashMap();

在实例化以后,底层创建了长度是16的一维数组Entry[] table

可能已经执行过多次put

map.put(key1,value1);

首先,调用key1所在类的hashCode()计算key1哈希值,次哈希值经过某算法计算以后,得到Entry数组中的存放位置

如果此位置上的数据为空,此时的key1-value1添加成功,以key作为判断标准是否添加---情况一

如果此位置上的数据不为空,(意味着次位置上存在一个或多个数据(以链表形式存在)),比较key1和已存在的一个或多个数据的哈希值:

如果key1的哈希值与已存在的数据的哈希值都不相同,此时key1-value1添加成功---情况二

如果key1的哈希值与已存在 的数据(key2=value2 ) 的哈希值都相同,继续比较:调用key1所在类的equals()方法:比较:如果equals()返回false:此时key1-value1添加成功----情况三

如果equals()返回true:使用value1替换value2 ----情况四

补充:关于情况二和情况三:此时key1-value1和原来的数据以链表的方式存储

在不断添加过程中,会涉及到的扩容问题当超出临界值,且要存放的位置非空 ,默认扩容是扩大为原来的2倍,并将元素复制过来

jdk8:数组+链表+红黑树

相较于7不同:

1 new HashMap():底层没有创建一个长度为16的数组

2 jdk8底层的数组是:Node[] 而非Entry[]

3首次调用put()方法时,底层创建长度为16的数组

4当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组的长度>64时,此时此索引位置上的所有数据改为使用红黑树存储

1.默认容量

代码:static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

定义:如果不指定HashMap初始化时的容量,则容量为默认值16;<<是位运算符,这里表示二进制1向左位移4位变为10000,也就是16;

2.最大容量

代码:static final int MAXIMUM_CAPACITY = 1 << 30;

定义:HashMap中桶的最大数量为2的30次方,如果初始化时或者向HashMap添加键值对超过这个数字都将设置为最大容量。

3.默认装载因子

代码:static final float DEFAULT_LOAD_FACTOR = 0.75f;

定义:初始化时不设置装载因子则默认为0.75

4.红黑树阈值

代码:static final int TREEIFY_THRESHOLD = 8;

定义:当桶中链表的长度大于且等于8时,链表将会自动转换为红黑树。

5.最小树化容量

代码:static final int MIN_TREEIFY_CAPACITY = 64;

定义:桶的容量大于且等于64并且达到红黑树阈值才会树化

6 扩容的临界值

threshold