Skip to content

Commit 4538611

Browse files
committed
Add note about HashMap
1 parent 70b8053 commit 4538611

File tree

3 files changed

+128
-1
lines changed

3 files changed

+128
-1
lines changed

java/basic/java-basic.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,11 @@ Throwable 可以用来表示任何可以作为异常抛出的类,分为两种
13651365
- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
13661366
- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
13671367

1368+
* IllegalStateException
1369+
```
1370+
在不合理或不正确时间内唤醒一个方法时出现的异常信息,英文意思是无效状态异常,比如在服务器已经返回数据给客户端了,这时候想修改字符集参数,就会报这样的错误。
1371+
```
1372+
13681373
# 九泛型
13691374
类型的参数化,就是可以把类型像方法的参数那样传递。泛型使编译器可以在编译期间对类型进行检查以提高类型安全,减少运行时由于对象类型不匹配引发的异常。
13701375

java/basic/java-collection.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,10 +791,130 @@ void putAll(Map<? extends K, ? extends V> m);
791791
V remove(Object key);
792792
int size();
793793
Collections<V> values(); // 返回value的结合,values是重复的
794+
795+
// Map中还有一个内置的接口 Map#entrySet()
796+
interface Entry<K,V> {
797+
K getKey();
798+
V getValue();
799+
int hashCode();
800+
V setValue(V);
801+
boolean equals(Object obj)
802+
}
794803
```
795804
796805
#### AbstractMap接口源码解析
806+
AbstractMap实现了Map接口,实现了一些通用的方法
807+
808+
`源码解析`
809+
```java
810+
// 巧妙的写法
811+
private static boolean eq(Object o1, Object o2) {
812+
return o1 == null ? o2 == null : o1.equals(o2);
813+
}
814+
```
815+
797816
##### HashMap源码解析和使用
817+
818+
`源码解析`
819+
```java
820+
// 数据存储在这里,一个叫table的变量中
821+
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
822+
// 看下Entry的定义,每一个Entry是一个单向链表
823+
static class Entry<K,V> implements Map.Entry<K,V> {
824+
final K key;
825+
V value;
826+
Entry<K,V> next;
827+
int hash;
828+
829+
/**
830+
* Creates new entry.
831+
*/
832+
Entry(int h, K k, V v, Entry<K,V> n) {
833+
value = v;
834+
next = n;
835+
key = k;
836+
hash = h;
837+
}
838+
}
839+
// 接下来我们就看下HashMap是如何存储值的。我们都知道HashMap中使用put(K k, V v)来存储值
840+
public V put(K key, V value) {
841+
if (table == EMPTY_TABLE) {
842+
inflateTable(threshold);
843+
}
844+
if (key == null)
845+
return putForNullKey(value); // 存储null key,直接调价到table[0]中
846+
int hash = hash(key); // 首先根据key计算出hash值
847+
int i = indexFor(hash, table.length); // 再根据hash值,计算出数据索引,也就是Entry<K, V>在table中的索引
848+
// 然后根据索引找到table中的Entry(是一个单向链表),通过e.next循环遍历单项链表
849+
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
850+
Object k;
851+
// 将key与每一个Entry的key进行对比,哈希值进行对比,如果key已经存在就替换掉旧值,并且返回旧值
852+
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
853+
V oldValue = e.value;
854+
e.value = value;
855+
e.recordAccess(this);
856+
return oldValue;
857+
}
858+
}
859+
860+
modCount++;
861+
// 如果key不存在Entry链表中,就新建一个Entry
862+
addEntry(hash, key, value, i);
863+
return null;
864+
}
865+
866+
// addEntry的时候索引值为0,
867+
private V putForNullKey(V value) {
868+
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
869+
if (e.key == null) {
870+
V oldValue = e.value;
871+
e.value = value;
872+
e.recordAccess(this);
873+
return oldValue;
874+
}
875+
}
876+
modCount++;
877+
addEntry(0, null, value, 0);
878+
return null;
879+
}
880+
881+
// 在table中的index是0,所以HashMap有一个固定存储key为null的值,此位置为table的第一个位置
882+
void addEntry(int hash, K key, V value, int bucketIndex) {
883+
if ((size >= threshold) && (null != table[bucketIndex])) {
884+
resize(2 * table.length); // size翻倍
885+
hash = (null != key) ? hash(key) : 0;
886+
bucketIndex = indexFor(hash, table.length);
887+
}
888+
889+
createEntry(hash, key, value, bucketIndex);
890+
}
891+
892+
void createEntry(int hash, K key, V value, int bucketIndex) {
893+
Entry<K,V> e = table[bucketIndex];
894+
table[bucketIndex] = new Entry<>(hash, key, value, e);
895+
size++;
896+
}
897+
// 插入null值之后,循环调用Map#put方法插入1-18
898+
::hash:: 0 ::key:: null ::value:: 1 ::bucketIndex:: 0
899+
::hash:: 50 ::key:: 1 ::value:: value 1 ::bucketIndex:: 2
900+
::hash:: 49 ::key:: 2 ::value:: value 2 ::bucketIndex:: 1
901+
::hash:: 48 ::key:: 3 ::value:: value 3 ::bucketIndex:: 0
902+
::hash:: 55 ::key:: 4 ::value:: value 4 ::bucketIndex:: 7
903+
::hash:: 54 ::key:: 5 ::value:: value 5 ::bucketIndex:: 6
904+
::hash:: 53 ::key:: 6 ::value:: value 6 ::bucketIndex:: 5
905+
::hash:: 52 ::key:: 7 ::value:: value 7 ::bucketIndex:: 4
906+
::hash:: 59 ::key:: 8 ::value:: value 8 ::bucketIndex:: 11
907+
::hash:: 58 ::key:: 9 ::value:: value 9 ::bucketIndex:: 10
908+
::hash:: 1650 ::key:: 10 ::value:: value 10 ::bucketIndex:: 2
909+
::hash:: 1614 ::key:: 11 ::value:: value 11 ::bucketIndex:: 14
910+
::hash:: 1615 ::key:: 12 ::value:: value 12 ::bucketIndex:: 15
911+
::hash:: 1612 ::key:: 13 ::value:: value 13 ::bucketIndex:: 12
912+
::hash:: 1613 ::key:: 14 ::value:: value 14 ::bucketIndex:: 13
913+
::hash:: 1610 ::key:: 15 ::value:: value 15 ::bucketIndex:: 10
914+
::hash:: 1611 ::key:: 16 ::value:: value 16 ::bucketIndex:: 11
915+
::hash:: 1608 ::key:: 17 ::value:: value 17 ::bucketIndex:: 8
916+
```
917+
798918
##### WeakHashMap源码解析和使用
799919
##### TreeMap源码解析和使用
800920
##### Hashtable源码解析和使用

tool/btrace.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
1. btrace DEBUG: adding to boot classpath failed!
33
常见是由于系统安装的btrace版本和代码中引入的jar的版本不匹配,建议加载jar(/btrace/../build/)
44
2. Port 2020 unavailable.
5-
2020端口不可用,那就换一个:btrace pid -p port xxx.java
5+
2020端口不可用,那就换一个:btrace pid -p port xxx.java
6+
3. 当参数为泛型的时候,使用Object替换
7+
4. 在Windows中,使用cmd执行btrace命令,git bash执行不了

0 commit comments

Comments
 (0)