string final,不能追加,需要重新new一个
stringbuild,内容 可变,可以重新赋能,能够追加,空间不足创造一个更大的,然后复制过去
stringbufferbuild 线程安全
javac编译,字符串加号可以进行优化,去掉加号,组成一个字符串。
常量相加,当有变量时,stringbuild方式添加,返回的是堆中的地址
常量有重复,地址不变
加号和append 谁效率高
少量字符串加号
多了就append
集合:集合类存储的仅仅是对象的引用,并不存储对象本身。
Queue:实现栈和队列,
Set:不允许元素重复,通过hash和equls方法判断是否重复
hashcode可能相同,hashset无序,treeset排序,linkedHashset有序
hashset:底层基于hashmap
hashmap:无序
linkehashmap:有序
treehashmap:排序
hashtable和hashmap区别
线程
key是否为空
value是否为空
Hashtable和concurrentmap区别
给方法加了锁,锁的this,当前锁标识对象,锁住整个对象。
在colletiontions中synchronziedmap,将线程不安全的map转换为安全的map,也是锁住整个对象, 效率低
concurrentmap juc中
1.7
分段锁,线程安全,效率好。
1.8
节点锁,各个节点单独加锁。
怎么扩容
成倍扩容,新建一个老数组
传入初始容量,向上取。
map遍历,不支持一遍遍历,一遍删除修改,要并发异常。
底层原理
map底层是Node节点,因为它要存key-value
所以map底层其实是Node一个个节点拼成的?
hash计算,hashcode的计算,异或向右16位,右移16位,是为了避免hash冲突,且和原本的hash值
这是它设置的一些默认参数
默认容量16,向左4位,2的四次方,16
最大容量,向左30位,2的三十次方,所以map最大容量就是2的三十次方
默认负载均衡 0.75
差点没认出这三个,相当于一个阈值
TREEIFY_THRESHOLD 链表转树的阈值8
UNTREEIFY_THRESHOLD 树转链表-6
MIN_TREEIFY_CAPACITY 数组长度
转树的条件,数组大于64,链表大于8,两个条件都要满足
ctrl+f12查看当前类的所有方法,hashmap的构造方法
我们可以看到有参构造和无参构造,有参大家都看得懂撒,传入容器大小,然后一个是默认负载均衡0.75
无参我们去看看是怎么回事,只给了个负载均衡参数?应该是个空数组
最重要,问的最多就是hashmap的put和get方法,然后我们去源码看看,put用了putval这个方法,我们点进去看看putval,let is go!
有点长哈,tap是当前链表(其实就是hash表?我觉得就是hash表的意思,我这个不咋自信,不敢确定),node是传入节点
我们对源码进行解析,发现自己一个人还是看的懂的,只要对各个参数的意义理解到就没问题了。
把tablehash表的值赋给tap,判断是不是空,说明链表是空的,创建长度,给hash表,默认16。
不为空,则对p hash算法计算位置,长度-1余,如果节点没有值,把节点放进去就好了。
有值,对hash值是否一样,key是否一样,一样覆盖就行,然后我们就要判断key和value不相等,,else if 是不是树结构,instanceof,我也没咋懂啥意思,我猜是用来判断是不是TreeNode种类,进行一种种类判断,我觉得这个方法的意思就是这样,不然后面解释不通。是树结构,我们用树结构的put方法,不是则用链表,链表遍历判断,然后放值。
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
有点累了
get方法,列表不能为空
同时列表首节点一致,直接返回,不一致,看树还是链表,树则以树的形式返回,链表则遍历。
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}