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常用方法及遍历总结:
- List接口中带索引的方法【特有】
- public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上
- public E get(int index): 返回集合中指定位置的元素
- public E remove(int index): 移除列表中指定位置的元素,返回的是被移除的元素
- 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