文档章节

equals & hashCode

noob_fly
 noob_fly
发布于 02/12 17:57
字数 1128
阅读 3
收藏 0

equals() 与hasCode() 都定义在Object.java中。equals 默认使用“==”来比较对象。

    public boolean equals(Object obj) {
        return (this == obj);
    }
   
   public native int hashCode();

在对于hashCode()的javadoc中明确表明: hashCode是用在hash表中的。 equals相同,hashCode一定相同(但hashCode相同,equals不一定相同),这样有利于提高hash表的效率。

eg. 验证: hashCode相同,equals不一定相同


    public static void main(String[] args) {
        Long a  = 1L;
        Integer b = 1;
        System.out.println(b.hashCode() == a.hashCode()); // true
        System.out.println(b.equals(a)); // false

    }

执行结果: true、 false。

java.lang下各类的重写

对于String:     

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

对于Boolean: hashCode() 为定值: true->1231! fale -> 1237。 equals() 先判定是否是本类的实例再比较值。

 public int hashCode() {
        return value ? 1231 : 1237;
    }
    public boolean equals(Object obj) {
        if (obj instanceof Boolean) {
            return value == ((Boolean)obj).booleanValue();
        }
        return false;
    }

对于比Integer范围小的short、byte、char : hashCode() 直接强转int。 equals() 先判定是否是本类的实例再比较值。

   public int hashCode() {
        return (int)value;
    }

   public boolean equals(Object obj) {
        if (obj instanceof Short) {
            return value == ((Short)obj).shortValue();
        }
        return false;
    }

对于比Integer范围大的Long、float、double: 
             hashCode(): 则需要处理转换成int。float是处理为int;double是先处理为long,再用long取hashCode()的方式转int;
             equals():  Long是直接比较数值; 而float、double是要转成int进行比较(按javadoc中所述 需要考虑NaN的问题),NaN直接返回定值。

eg.

    public static void main(String[] args) {
        float a = Float.NaN;
        Float b = Float.NaN;
        System.out.println(a == b); // flase
        System.out.println(b.equals(b)); // true
        float a2 = 1f;
        Float b2 = 1f;
        System.out.println(a2 == b2); // true
        System.out.println(b2.equals(b2)); // true
    }

执行结果: false、true、true、true。 

NaN与任何浮点数(包括自身)的比较结果都为假,这是NaN独有的特性,所以可以使用与自己相比来确定当前数值是不是一个正常的数.

结论: 如果仅仅考虑非NaN的问题可以直接用floatValue()、doubleValue()方法。但因为float与double有NaN所以需要考虑!

源码如下:

Long:
   public static int hashCode(long value) {
        return (int)(value ^ (value >>> 32));
    } 
  public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }

Float: 

   /**
     * A constant holding a Not-a-Number (NaN) value of type
     * {@code float}.  It is equivalent to the value returned by
     * {@code Float.intBitsToFloat(0x7fc00000)}.
     */
  public static final float NaN = 0.0f / 0.0f;

  public static int hashCode(float value) {
        return floatToIntBits(value);
    }

   public boolean equals(Object obj) {
        return (obj instanceof Float)
               && (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
    }

    public static int floatToIntBits(float value) {
        int result = floatToRawIntBits(value);
        // Check for NaN based on values of bit fields, maximum
        // exponent and nonzero significand.
        if ( ((result & FloatConsts.EXP_BIT_MASK) ==
              FloatConsts.EXP_BIT_MASK) &&
             (result & FloatConsts.SIGNIF_BIT_MASK) != 0)
            result = 0x7fc00000;
        return result;
    }

Double:
    public int hashCode() {
        long bits = doubleToLongBits(value);
        return (int)(bits ^ (bits >>> 32));
    }

    public static long doubleToLongBits(double value) {
        long result = doubleToRawLongBits(value);
        // Check for NaN based on values of bit fields, maximum
        // exponent and nonzero significand.
        if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
              DoubleConsts.EXP_BIT_MASK) &&
             (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
            result = 0x7ff8000000000000L;
        return result;
    }

    /**
     * A constant holding a Not-a-Number (NaN) value of type
     * {@code double}. It is equivalent to the value returned by
     * {@code Double.longBitsToDouble(0x7ff8000000000000L)}.
     */
    public static final double NaN = 0.0d / 0.0;

equals和hashcode为什么要一起重写

维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。 

hashcode是用于散列数据的快速存取,如利用HashSet、HashMap、Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。

hashSet的核心就是通过HashMap的key来实现的

   /**
     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
        map = new HashMap<>();
    }

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

通过hashMap的源码可见: hash(Object key)对于定位对象在table的位置至关重要,其中就会使用对象的hashCode值。

    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

所以在老版本(1.7)hashMap的实现中对于hash定位相同的值将使用拉链法存储:存储table位置上的是一个Map.Entry对象链表。新值对如果hash定位相同,equals不同,则封装成Map.Entry对象将插入进该链表的头部,next指向链表原头部;该链表查找算法的时间复杂度为0(n)。而在1.8改为当链表长度超过TREEIFY_THRESHOLD(默认 8) <实则是9>则转为红黑树存储,因红黑树的特性,查找算法的时间复杂度为O(log2 n)。(hashTable的处理还是拉链法)

Collection的源码分析

© 著作权归作者所有

共有 人打赏支持
noob_fly
粉丝 5
博文 91
码字总数 104130
作品 0
广州
程序员
私信 提问
Java 中的equal()和hascode()方法

equals()反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。 而hashCode()是对象或变量通过哈希算法计算出的哈希值。 之所以有hashCode方法,是因...

vshcxl
2016/10/25
6
0
Java hashCode() 和 equals()的若干问题解答

本章的内容主要解决下面几个问题: 1、 equals() 的作用是什么? 2 、equals() 与 == 的区别是什么? 3、 hashCode() 的作用是什么? 4 、hashCode() 和 equals() 之间有什么联系? 第1部分 ...

刘诗书
2017/11/27
0
0
Java之hashCode()和equals()方法

程序世界和现实世界其实是一样的,相等和相同是不同的概念,就此简要说明一下其中的含义: 1 equals() 的作用是什么? 2 equals() 与 == 的区别是什么? 3 hashCode() 的作用是什么? 4 hash...

董广明
2014/04/01
0
3
equals和hashCode的区别和联系

一、前言 前段时间使用list.remove(obj)的时候重写了obj的equals方法,因为list的remove是以equals来判断标准的。但是,今天被公司的代码扫描工具提示未重写hashCode方法!!之前准备面试时也...

叫我宫城大人
2017/08/23
0
0
hashCode() 和 equals()

第1部分 equals() 的作用 equals() 的作用是 用来判断两个对象是否相等。 equals() 定义在JDK的Object.java中。通过判断两个对象的地址是否相等(即,是否是同一个对象)来区分它们是否相等。源...

小菜鸡1
2016/08/17
15
0

没有更多内容

加载失败,请刷新页面

加载更多

使用keepalived实现nginx的高可用

概述 是这样子的,我想让家中所有的应用服务都从nginx中出去,让nginx处于访问的最边缘地带,为了让nginx可靠性加强,所以nginx就得实现高可用,分别是下面两台机器要做nginx的集群 10.10.10...

bboysoulcn
今天
1
0
Mysql索引机制B+Tree

1、问题引入 有一个用户表,为了查询的效率,需要基于id去构建索引。构建索引我们需要考虑两个方面的问题,1个是查询的效率,1个是索引数据的存储问题。该表的记录需要支持百万、千万、甚至上...

万山红遍
今天
40
0
RDD

1.概念: RDD是spark整个体系中最基础核心的概念,RDD(Resilient Distributed DataSet)即弹性分布式数据集 弹性: RDD支持横向多分区,纵向操作内存不足写入磁盘,hdfs等,实现数据在内存和...

仟昭
今天
1
0
springboot整合mycat

动态数据源项目整合 Maven依赖信息 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relat......

须臾之余
今天
2
0
深入解析Vue 和微信小程序的区别、比较

写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别。 一、生命周期 先贴两张图: vue生命周期 小程序生命周期 相比之下,小程序的钩子函数要简单得多。 vue的...

前端攻城小牛
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部