Android中的HashMap原理实践探索,重写equals(),为什么重写hashCode() 和 ==

本文通过实践探索Android中HashMap的实现原理,揭示了为何需要重写equals()和hashCode()。分析了HashMap在Android不同版本的差异,包括初始化容量和扩容策略。通过实例展示了当Key相同但Value不同时,如何利用HashSet和HashMap进行对象比较。文中还讨论了哈希冲突和解决策略,并提醒在特定场景下重写equals()和hashCode()的必要性。
摘要由CSDN通过智能技术生成

HashMap的文章有很多
可以先读读相关文章,及原理篇。本篇主要是从实践探索里面的变化,再对比看原理就会更加清晰.

此话题虽然老生常谈:然而理论完了实践一把
其中不少收获,Android中的和Java的设计还是有所不同。
Android给的英文注释也是16,实践一把发现注释欺骗了你。
实践是检验真理的唯一标准。于是还是实践一把,验证一下,扩容因子,以及扩容演化,运算的过程步骤。
Android初始化数组不是16 各版本不一样
之前的是4,后来变成0,第一次put才给4.Android对内存的使用考虑是慎之又慎。
而且里面用到很多巧妙的位运算
和数据结构,算法设计。故而HashMap的探讨真是前赴后继,乐此不疲。
周末提起,又探究一翻,主要利用反射打印其变化过程。明白了其中不少道理,受益匪浅,其中一些位运算算法还未理解其精髓。这个若详细探究起来几天几夜也未必,做了个简易探索。有兴趣的可以一观, 不足之处,还望指正

HashMap 有局限不能查询区间问题。
Java8又用到红黑树。
前天翻书数据结构,说二叉树深度过大时出现了B树B+树。用于数据库之中,使用少量内存查询更高效查询对象。

相关文章
HashMap实现原理及源码分析
http://www.cnblogs.com/chengxiao/p/6059914.html
Java8系列之重新认识HashMap
https://zhuanlan.zhihu.com/p/21673805
HashMap的工作原理 提问篇
http://www.importnew.com/7099.html
深入Java集合学习系列:HashMap的实现原理
http://zhangshixi.iteye.com/blog/672697
HashMap实现原理分析(详解)
http://www.cnblogs.com/xingzc/p/5765572.html

从零 == 号开始吧
来来看例子

public static void main(String[] args) {
        String  ss = "a";
        int hashCode = ss.hashCode();
        String s2 = "a";
        int hashCode2 = s2.hashCode();
        System.out.println(hashCode);
        System.out.println(hashCode2);

        System.out.println(ss == s2);
        System.out.println(ss.equals(s2));
 }
运行结果
97
97
true
true

看例子

 public static void main(String[] args) {
        String  ss = "a";
        int hashCode = ss.hashCode();
        System.out.println(hashCode);
        String s2 = new String("a");
        System.out.println(s2.hashCode());

        System.out.println(ss == s2);
        System.out.println(ss.equals(s2));
 }
 运行结果
97
97
false
true

对比

 public static void main(String[] args) {

        String ss = new String("a");
        int hashCode = ss.hashCode();
        System.out.println(hashCode);
        String s2 = new String("a");
        System.out.println(s2.hashCode());

        System.out.println(ss == s2);
        System.out.println(ss.equals(s2));
 }
运行结果
97
97
false
true

放在Set集合里面

 public static void main(String[] args) {
        String  ss = "a";
        String s2 = "a";
        String s3 = new String("a");
        String s4 = new String("a");
        Set set = new HashSet();
//      Set set = new TreeSet();
        set.add(ss);
        set.add(s2);
        set.add(s3);
        set.add(s4);

        for (Object object : set) {
            System.out.println("set.size()===" + set.size() + " ;  object=="+ object);
        }
 }

运行结果

set.size()===1 ;  object==a

在Set里面认为对象相等。

HashSet实现是利用了HashMap去进行的比较 看Add方法 ; 利用了静态全局变量 Value为相同的值 如果Key相同那么map中只有一个对象 ; 我们再看HashMap的put方法。
  private transient HashMap<E,Object> map;

  private static final Object PRESENT = new Object();

  public HashSet() {
        map = new HashMap<>();
    }

  public boolean add(E e) {
     return map.put(e, PRESENT)==null;
  }

HashMap上场 , HashMap有多个版本,Android中的不同版本JDK24和JDK25不同
初始化容量也不同 不是我们看到的Java的16.
Java7和Java8的也不同 Java8用到红黑树等 默认的扩容因子还都是0.75
版本对比先不比较,比较了一个晚上都凌乱了。
HashMap put方法源码
先看AndroidSDK 25版本中的HashMap源码
自己点进去看一下。我们利用反射先看看初始化的属性
HashMap 网上原理一大堆没看一次,大有受益又有疑问,
实践是检验真理的唯一标准,我们来实践一下。
我们采用实践通过实践看原理

先建一个空的HashMap 反射一下

HashMap hashMap = new HashMap();
ReflectUtils.getFildValue(hashMap);

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class ReflectUtils {
    public static void getFildValue(Object object) {
        Field[] fields = object.getClass().getDeclaredFields();
        System.out.println("----------------------start----------------------------------------------------------------------------");
        System.out.println("class :" + object.getClass());
        for(Field f : fields){
            f.setAccessible(true);
            int mod = f.getModifiers();

            Object o = null;
            try {
                o = f.get(object);
                System.out.println( Modifier.toString(mod) + " " + f.getType().getName() + " " + f.getName() + " == " + o);
                if (o != null) {
                    Class<?> type = o.getClass();
                    if (type.isArray()) {
                        System.out.println("是数组:"+type.isArray());
                        Class<?> elementType = type.getComponentType();
                        System.out.println("Array of: " + elementType);
                        System.out.println("Array length: " + Array.getLength(o));
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            System.out.println("------------------------");


        }
        System.out.println("----------------------end-------------------------------------------------------------------------");
    }
}

然后我们看到各种的初始化的值 对于static final的不会改变 以后就不再打印
I/System.out: transient [Ljava.util.HashMap HashMapEntry;table==[Ljava.util.HashMap HashMapEntry;@6ca7431
这个是数组。

不会变化的  记住就行
static final int DEFAULT_INITIAL_CAPACITY = 4; //默认初始化容量
static final int MAXIMUM_CAPACITY = 1 << 30; // 最大容量
static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认扩容因子
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值