Java 对象比较equals方法和“==“

目录

一、equals方法和"=="的区别

1.1 "=="比较

1.2 equals方法

1.2.2 类重写了equals方法

二、hashCode方法      

2.1 HashSet的add方法

   2.2 HashMap的put方法     


一、equals方法和"=="的区别

1.1 "=="比较

        如果是基本数据类型,则 == 比较的是值;

        如果是对象类型,则 == 比较的是对象的地址。

        注意:指向字符串常量池里面的字符串引用,使用"=="进行比较,结果为true

https://www.jb51.net/article/224268.htmhttps://www.jb51.net/article/224268.htm

1.2 equals方法

1.2.1 不重写eqluals方法

        使用的是Object类的equals方法实现,Object的equals(Object obj)方法:直接使用"=="进行比较(和直接使用"=="没有差异);

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

1.2.2 类重写了equals方法

        Java中已经有很多类重写了equals方法,如String.class、AbstractList、AbstractMap、AbstractSet等;

        举例:String.class

         先用"=="比较地址是否相同,相同就返回,否则不同继续比较。如果anObject类型不对,直接返回false;如果同为字符串,长度不同也返回false,否则逐一比较每一个字符是否相同,一有不同就返回false。

        总结:地址>类型>长度>值

    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) {
                // 字符串长度不同,就可定不相等返回false
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    // 逐个字符比较,有一个不相等就返回false
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

        举例:AbstractList.class

        还是先比较地址,然后是否是同一类型,值逐一比较,最后判断是否都遍历完(长度是否相同)。

        总结:地址>类型>长度>值

public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof List))
            return false;

        ListIterator<E> e1 = listIterator();
        ListIterator<?> e2 = ((List<?>) o).listIterator();
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
    }

二、hashCode方法      

       一般重写了equals方法时,需要同时重写hashCode方法,这主要是为了保证Java里面散列集合的使用,主要是key去重,比如HashSet(value一直为同一常量的HashMap)、HashMap等。

        Object的hashCode()方法,native方法;        

public native int hashCode();

2.1 HashSet的add方法

        底层调用了HashMap的put方法,只是value为常量对象

private static final Object PRESENT = new Object();

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

   2.2 HashMap的put方法     

        HashMap的key实质是传入的key所对应的hashCode值,通过这个hashCode值找到tab数组下标处的值(链表),再来判断这个key是否存在,执行插入,还是修改操作。

    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);
    }

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

        因此hashCode方法格外重要,很多Java类,已经重写了hashCode方法,比如String.class

        举例:String.class         

        可以发现,计算hashcode的最主要代码是 h = 31 * h + val[i]; 

         公式为: hashcode=\sum_{i=0}^{length-1}val[i]*31^{n-i-1}

         为什么是31?

         答案:String hashCode 方法为什么选择数字31作为乘子 | 田小波的技术博客

    /**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */   
     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;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值