1.String类:
实现了serilizable,可比接口,seriliazable仅用于标志,具有可比性的comparableTo方法用于比较字符串大小。
底层是通过final char []实现字符串的,其所有方法基本是用字符数组相关方法实现的。
2.ArrayList:
实现了列表,RandomAccess的,克隆,serilizable接口,ArrayList的底层由动态数组实现,初始数组长度为0时,当第一次添加元素时就会扩容到10,也可以调用者自己赋初始数组容量。(调用者如果赋初始容量,那初始容量最小为10,即(调用者赋值小于10则初始容量为10)。当添加元素到集合大小时扩容到1.5倍。其他的ArrayList集合方法效率和数组特性有关,比如删除方法,需要删除指定位置的元素,将其后的元素向前移位,这时间复杂度很大的事,所以效率低,同样的在指定位置插入元素效率同样低。这就是我们说的ArrayList的集合可以快速改查,但是增删效率低下。
ArrayList的是线程不安全的原因:当集合添加元素时,由需要执行两步,第一判断集合容量是否能容下该元素,然后再添加元素,比如集合容量初始容量为10,当集合恰好到9时,一个线程判断集合容量可进行增加操作,然后另一个线程又进行了判断可进行增加操作,当两个线程都进行了添加操作,数组就越界了。还有一种就是当一个线程判断容量后和另一个线程也判断了容量同时进行插入时,会将数组的一个角标位赋两次值,后一次会覆盖前一次,导致添加了了两次而集合只添加了一个元素。
object的toArray()方法可能会出异常的,这是因为多态导致的对象[]数组中可能存的是对象子类,当其用toArray()方法时,返回的就是其子类数组,导致对象向下转型,而向下转型是有可能会出错的。
3.LinkedList:
LinkedList是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈,队列或双端队列进行操作。
LinkedList实现List接口,能对其进行队列操作。
LinkedList实现Deque接口,即能将LinkedList当作双端队列使用。
LinkedList实现了Cloneable接口,即覆盖了函数clone(),能浅克隆。
LinkedList实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList是线程不安全的。
链表的访问特定位置元素,是利用类似折半查找的方法。因为双向链表只有前驱后继是没有角标的,想要查找到特定位置,只能遍历。
链表可以快速增删,这和链表的特有性关,再增加或删除一个元素时,只需改变其和相邻的元素的前驱后继。
4.HashSet:
HashSet的是基于HashMap中实现的,关键为出入元素的hashCode时数值为存入的元素,因为HashMap中的关键值不能重复,所以得到了HashSet中的不可存入重复元素的特性。所以其特性通过HashMap中即可了解.HashSet线程不安全。
5.HashMap:
HashMap中以输入数组和链表组成的,入口有四个属性,键,值,nextEntry,的hashCode组成。如下图,补充一点,当一个链表长度大于8时,后面存入的数据就会采用红黑树的方式,加快检索方式,当树的节点少于6时又会反树化,变成链表。
下图来源博客地址
HashMap的初始容量为16,每次扩容加倍,负载因子为0.75,容量为2的倍数是为了保证低位的散列均匀。
key.hashCode()---> hashCode ---> hash()---> hash --- indexFor()---> Entry []下标,使用key本身的hashCode方法得到一个的key的散列码,hash()方法是将key的散列码转化成一个实际的数字(将的hashCode >>> 16再与的hashCode按位异或)得到一个散列值,indexFor()方法内部是用ħ和数组长度-1进行按位与&操作,即得到了entry数组下标。为了让entry数组每个链表尽量均匀分布,所以HashMap中的容量为2的倍数。
有理解不对的地方欢迎大家多多指正。
2018年10月21日
HashMap中需要扩容时,会重新计算输入的下标,相当于从以上红字步骤中的indexFor()再跑一遍,这样扩容后的数组才会均匀分布,并减少链表的长度。所以扩容是很费时间的操作,在可以明确HashMap大小时,尽量在新的HashMap()时指定容量大小。
2018年10月31日