HashMap及HashTable源码解析,Android-Camera内存问题剖析

  1. static final Entry<?,?>[] EMPTY_TABLE = {};

  2. /**

  3. * The table, resized as necessary. Length MUST Always be a power of two.

  4. */

  5. transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;

  6. /**

  7. * The number of key-value mappings contained in this map.

  8. */

  9. transient int size;

  10. /**

  11. * The next size value at which to resize (capacity * load factor).

  12. * @serial

  13. */

  14. // If table == EMPTY_TABLE then this is the initial capacity at which the

  15. // table will be created when inflated.

  16. int threshold;

下面讲解几个比较重要的方法

1)当我们进行put操作的时候

先贴出源码

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public V put(K key, V value) {

  2. if (key == null)

  3. return putForNullKey(value); //处理null值

  4. int hash = hash(key.hashCode());//计算hash

  5. int i = indexFor(hash, table.length);//计算在数组中的存储位置

  6. //遍历table[i]位置的链表,查找相同的key,若找到则使用新的value替换掉原来的oldValue并返回oldValue

  7. for (Entry<K,V> e = table[i]; e != null; e = e.next) {

  8. Object k;

  9. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

  10. V oldValue = e.value;

  11. e.value = value;

  12. e.recordAccess(this);

  13. return oldValue;

  14. }

  15. }

  16. //若没有在table[i]位置找到相同的key,则添加key到table[i]位置,新的元素总是在table[i]位置的第一个元素,原来的元素后移

  17. modCount++;

  18. addEntry(hash, key, value, i);

  19. return null;

  20. }

a HashMap会对null值key进行特殊处理,总是放到table[0]位置

b计算has值

c 找到在table数组中的索引

1)遍历table[i]位置的链表,查找相同的key,若找到则使用新的value替换掉原来的oldValue并返回oldValue

2)若没有在table[i]位置找到相同的key,则添加key到table[i]位置,新的元素总是在table[i]位置的第一个元素,原来的元素后调用addEntry方法

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. void addEntry(int hash, K key, V value, int bucketIndex) {

  2. if ((size >= threshold) && (null != table[bucketIndex])) {

  3. resize(2 * table.length);

  4. hash = (null != key) ? hash(key) : 0;

  5. bucketIndex = indexFor(hash, table.length);

  6. }

  7. createEntry(hash, key, value, bucketIndex);

  8. }

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. void createEntry(int hash, K key, V value, int bucketIndex) {

  2. Entry<K,V> e = table[bucketIndex];

  3. table[bucketIndex] = new Entry<>(hash, key, value, e);

  4. size++;

  5. }

所做的工作就是:

1)判断当元素数量达到临界值(capactiy*factor)时,则进行扩容,是table数组长度变为table.length*2

2)当table[index]已存在其它元素时,会在table[index]位置形成一个链表,将新添加的元素放在table[index],原来的元素通过Entry的next进行链接,这样以链表形式解决hash冲突问题,

**2)get方法

**同样当key为null时会进行特殊处理,在table[0]的链表上查找key为null的元素

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public V get(Object key) {

  2. if (key == null)

  3. return getForNullKey();

  4. Entry<K,V> entry = getEntry(key);

  5. return null == entry ? null : entry.getValue();

  6. }

get的过程是先计算hash然后通过hash与table.length取摸计算index值,然后遍历table[index]上的链表,直到找到key,

然后返回,找不到返回null

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. final Entry<K,V> getEntry(Object key) {

  2. if (size == 0) {

  3. return null;

  4. }

  5. int hash = (key == null) ? 0 : hash(key);

  6. for (Entry<K,V> e = table[indexFor(hash, table.length)];

  7. e != null;

  8. e = e.next) {

  9. Object k;

  10. if (e.hash == hash &&

  11. ((k = e.key) == key || (key != null && key.equals(k))))

  12. return e;

  13. }

  14. return null;

  15. }

3)remove方法

remove方法和put get类似,计算hash,计算index,然后遍历查找,将找到的元素从table[index]链表移除

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public V remove(Object key) {

  2. Entry<K,V> e = removeEntryForKey(key);

  3. return (e == null ? null : e.value);

  4. }

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. final Entry<K,V> removeEntryForKey(Object key) {

  2. if (size == 0) {

  3. return null;

  4. }

  5. int hash = (key == null) ? 0 : hash(key);

  6. int i = indexFor(hash, table.length);

  7. Entry<K,V> prev = table[i];

  8. Entry<K,V> e = prev;

  9. while (e != null) {

  10. Entry<K,V> next = e.next;

  11. Object k;

  12. if (e.hash == hash &&

  13. ((k = e.key) == key || (key != null && key.equals(k)))) {

  14. modCount++;

  15. size–;

  16. if (prev == e)

  17. table[i] = next;

  18. else

  19. prev.next = next;

  20. e.recordRemoval(this);

  21. return e;

  22. }

  23. prev = e;

  24. e = next;

  25. }

  26. return e;

  27. }

4)clear()方法

clear方法非常简单,就是遍历table然后把每个位置置为null,同时修改元素个数为0

需要注意的是clear方法只会清楚里面的元素,并不会重置capactiy

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public void clear() {

  2. modCount++;

  3. Arrays.fill(table, null);

  4. size = 0;

  5. }

5)containsKey和containsValue

containsKey方法是先计算hash然后使用hash和table.length取摸得到index值,遍历table[index]元素查找是否包含key相同的值

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public boolean containsKey(Object key) {

  2. return getEntry(key) != null;

  3. }

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. final Entry<K,V> getEntry(Object key) {

  2. if (size == 0) {

  3. return null;

  4. }

  5. int hash = (key == null) ? 0 : hash(key);

  6. for (Entry<K,V> e = table[indexFor(hash, table.length)];

  7. e != null;

  8. e = e.next) {

  9. Object k;

  10. if (e.hash == hash &&

  11. ((k = e.key) == key || (key != null && key.equals(k))))

  12. return e;

  13. }

  14. return null;

  15. }

6)containsValue方法就比较粗暴了,就是直接遍历所有元素直到找到value,由此可见HashMap的containsValue方法本质上和普通数组和list的contains方法没什么区别,你别指望它会像containsKey那么高效

[java] view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public boolean containsValue(Object value) {

  2. // Same idea as size()

  3. if (value == null)

  4. throw new NullPointerException();

  5. final Segment<K,V>[] segments = this.segments;

  6. boolean found = false;

  7. long last = 0;

  8. int retries = -1;

  9. try {

  10. outer: for (;😉 {

  11. if (retries++ == RETRIES_BEFORE_LOCK) {

  12. for (int j = 0; j < segments.length; ++j)

  13. ensureSegment(j).lock(); // force creation

  14. }

  15. long hashSum = 0L;

  16. int sum = 0;

  17. for (int j = 0; j < segments.length; ++j) {

  18. HashEntry<K,V>[] tab;

  19. Segment<K,V> seg = segmentAt(segments, j);

  20. if (seg != null && (tab = seg.table) != null) {

  21. for (int i = 0 ; i < tab.length; i++) {

  22. HashEntry<K,V> e;

  23. for (e = entryAt(tab, i); e != null; e = e.next) {

  24. V v = e.value;

  25. if (v != null && value.equals(v)) {

  26. found = true;

  27. break outer;

  28. }

  29. }

  30. }

  31. sum += seg.modCount;

  32. }

  33. }

  34. if (retries > 0 && sum == last)

  35. break;

  36. last = sum;

  37. }

  38. finally {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

sum += seg.modCount;

  1. }

  2. }

  3. if (retries > 0 && sum == last)

  4. break;

  5. last = sum;

  6. }

  7. finally {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-4eDyxO4H-1710968938036)]
[外链图片转存中…(img-wZ23ilYn-1710968938037)]
[外链图片转存中…(img-kUPwECqi-1710968938037)]
[外链图片转存中…(img-PIuIKT9h-1710968938038)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-RbLb7tyi-1710968938038)]

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值