详谈Map的key、value值的数据类型不能为基本类型的原因

interface Map<K,V>

Map源码

  /**
     * Returns the hash code value for this map entry. The hash code
     * of a map entry <tt>e</tt> is defined to be: <pre>
     *   (e.getKey()==null  ? 0 : e.getKey().hashCode()) ^
     *   (e.getValue()==null ? 0 : e.getValue().hashCode())
     * </pre>
     * This ensures that <tt>e1.equals(e2)</tt> implies that
     * <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries
     * <tt>e1</tt> and <tt>e2</tt>, as required by the general
     * contract of <tt>Object.hashCode</tt>.
     *
     * @return the hash code value for this map entry
     * @see Object#hashCode()
     * @see Object#equals(Object)
     * @see #equals(Object)
  */
    int hashCode();

hashCode返回 (e.getKey()==null ? 0 : e.getKey().hashCode()) ^(e.getValue()==null ? 0 : e.getValue().hashCode())

class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable

HashMap源码中:

public final int hashCode() {
 return Objects.hashCode(key) ^ Objects.hashCode(value);
}
static final int hash(Object key) {
 int h;
 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public final boolean equals(Object o) {
 if (o == this)
    return true;
  if (o instanceof Map.Entry) {
    Map.Entry<?,?> e = (Map.Entry<?,?>)o;
  if (Objects.equals(key, e.getKey()) &&
    Objects.equals(value, e.getValue()))
    return true;
  }
  return false;
}

补充知识:java hashmap key long 和int 区别

最近同事问起,map里面存的key 是int 类型的,存了一个 Integera =123,为什么使用long 123 作为key get,取出来的是空,这个问题粗想了一下,感觉long和int 本身 类型不同,肯定不能是同一个key,后来细研究了一下,跟了一下源码,发现逻辑不是那么简单。

简单测试了一下,如下代码

Map<Object,String> map = new HashMap<>();
Integer b = 123;
Long c =123L;
map.put(b, b+"int");
System.out.println(b.hashCode() == c.hashCode()); //true
System.out.println(map.get(c));  //null
map.put(c, c+"long"); // size =2

简单的总结了一下问题:

1、HashMap 是把key做hash 然后作为数组下标,但是 b 和c 的hashcode 竟然是相同的,为什么 get(c) 为空

2、HashMap 存入c 发现 size=2 ,hashcode相同 为什么 size=2,get(c) =123long

带着上面两个问题跟了一遍源码,问题豁然开朗

1、hashmap在存入的时候,先对key 做一遍 hash,以hash值作为数组下标,如果发现 下标已有值,判断 存的key 跟传入的key是不是相同,使用 (k = p.key) == key || (key != null && key.equals(k)) ,如果相同覆盖,而Interger的equals 方法如下:

if (obj instanceof Integer) {
      return value == ((Integer)obj).intValue();
    }

return false;

Integer 和 Long 肯定不是一个类型,返回 false,这时候 hashmap 以 hashkey 冲突来处理,存入链表,所以 Long 123 和 Integer 123 hashmap会认为是 hash冲突

2、hashmap 在 get的时候,也是先做 hash处理,根据hash值查找对应的数组下标,如果找到,使用存入时候的判断条件

(k = first.key) == key || (key != null && key.equals(k)) 如果相等就返回,不相等,查找当前值的next有没有值,有继续根据逻辑判断,所以 存入Integer 123 根据 Long 123 来获取返回的 是 NULL

至此,解析完毕。

以上这篇详谈Map的key、value值的数据类型不能为基本类型的原因就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • JAVA抛出异常的三种形式详解

    一.系统自动抛出异常 当程序语句出现一些逻辑错误.主义错误或者类型转换错误时,系统会自动抛出异常 例一 public static void main(String[] args) { int a = 5; int b = 0; System.out.println( a / b); } 运行结果,系统会自动抛出ArithmeticException异常 Exception in thread "main" java.lang.ArithmeticException: / by zer

  • JAVA异常处理捕获与抛出原理解析

    JAVA 异常 当代码运行出现错误导致程序终止运行或出现错误情况的状况,就是异常.异常不是指语法错误,即不属于编译错误,只有运行的程序才会有异常. 这个时候,JAVA 就提供了优秀的处理方法:异常处理 异常处理能让程序在异常发生时,按照异常处理设定的逻辑对异常进行处理,最大程度保证程序继续运行,并且显示并处理异常. JAVA 程序发生异常,就会用对应的异常类的对象来封装异常,JRE(Java Runtime Environment) 便会寻找对应的异常处理逻辑来处理该异常. 总的说来,异常处理机

  • 浅谈Map集合中get不存在的key值,会抛出异常吗?

    我就废话不多说了,大家还是直接看代码吧~ public static void main(String[] args) { Map<String, String> a = new HashMap<String, String>(); String string = a.get("a111"); System.out.println(string); } 在Map集合中,get一个不存在的值,不会抛出异常,获得的返回值为null. 补充知识:map中get不存在的

  • Java8 Map中新增的方法使用总结

    前言 得益于 Java 8 的 default 方法特性,Java 8 对 Map 增加了不少实用的默认方法,像 getOrDefault, forEach, replace, replaceAll, putIfAbsent, remove(key, value), computeIfPresent, computeIfAbsent, compute 和merge 方法.另外与 Map 相关的 Map.Entry 也新加了多个版本的 comparingByKey 和 comparingByVal

  • 详谈Map的key、value值的数据类型不能为基本类型的原因

    interface Map<K,V> Map源码 /** * Returns the hash code value for this map entry. The hash code * of a map entry <tt>e</tt> is defined to be: <pre> * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ * (e.getValue()==null ? 0 : e.getVa

  • Java中对list map根据map某个key值进行排序的方法

    实例如下所示: package test; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; public class java_ListMapSort { public static void main(String[] args)

  • 基于C++ map中key使用指针问题的详解

    C++实际开发的过程会经常使用到map.map是一个key-value值对,key唯一,可以用find进行快速的查找.其时间复杂度为O(logN),如果采用for循环进行遍历数据时间复杂度为O(N).如果map中的数据量比较少时,采用find和for循环遍历的效率基本没有太大的区别,但是在实际的开发过程中,存储在map中的数据往往是大量的,这个时候map采用find方式效率比遍历效率高的多. 确定采用find方式查找数据后,我们需要考虑存储map的空间复杂度,对于基础数据类型的数据(int ch

  • Java Map 按key排序和按Value排序的实现方法

    一.理论准备 Map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等. TreeMap:基于红黑树(Red-Black tree)的 NavigableMap 实现,该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法. HashMap的值是没有顺序的,它是按照key的HashCode来实现的,对于这个无序的HashMap我们要怎么来实现排序呢?参照TreeM

  • Java Map 按Key排序实例代码

    Java Map 按Key排序 有时候我们业务上需要对map里面的值按照key的大小来进行排序的时候我们就可以利用如下方法来进行排序了, package test; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; impo

  • Android 对Map按key和value分别排序的实例

    一. 理论准备 Map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等. TreeMap:基于红黑树(Red-Black tree)的 NavigableMap 实现,该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法. HashMap的值是没有顺序的,它是按照key的HashCode来实现的,对于这个无序的HashMap我们要怎么来实现排序呢?参照Tree

  • java8 stream 操作map根据key或者value排序的实现

    引言 最近小编自己一个人在负责一个项目的后台开发,其中有一部分是统计相关的功能,所以需要一些排序或者分组的操作,之前这种操作小编觉得还是比较麻烦的,虽热有一些现成的工具类,但是工具类的写法也是比较复杂的,但是如果使用java8 stream流的话就比较简单了,并且代码量会大大的减少,下面总结几个对map的操作. 1.map 根据value排序 Map<String,BigDecimal> map =new HashMap<>(); map.put("one",

  • 详解JAVA里面获取map的key和value的方法

    获取map的key和value的方法分为两种形式: map.keySet():先获取map的key,然后根据key获取对应的value: map..entrySet():同时查询map的key和value,只需要查询一次. 同时遍历key和value时,keySet与entrySet方法的性能差异取决于key的具体情况,如复杂度(复杂对象).离散度.冲突率等.换言之,取决于HashMap查找value的开销.entrySet一次性取出所有key和value的操作是有性能开销的,当这个损失小于Ha

  • golang 如何获取map所有key的方式

    最佳方式:根据map的长度,新建一个数组,遍历map逐个压入 方法1(效率很高): func getKeys1(m map[int]int) []int { // 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高 j := 0 keys := make([]int, len(m)) for k := range m { keys[j] = k j++ } return keys } 方法2(效率很高): func getKeys2(m map[int]int) [

  • Vue 中为什么不推荐用index 做 key属性值

    目录 前言 key 的作用 key 在 diff 算法中的角色 同步头部节点 同步尾部节点 添加新的节点 删除多余节点 最长递增子序列 为什么不要用 index 性能消耗 数据错位 解决方案 总结 前言 前端开发中,只要涉及到列表渲染,那么无论是 React 还是 Vue 框架,都会提示或要求每个列表项使用唯一的 key,那很多开发者就会直接使用数组的 index 作为 key 的值,而并不知道 key 的原理.那么这篇文章就会讲解 key 的作用以及为什么最好不要使用 index 作为 key

随机推荐