美文网首页
Java:== 、equals()和hashCode()

Java:== 、equals()和hashCode()

作者: renyjenny | 来源:发表于2018-06-04 19:38 被阅读0次

    ==

    根据我的理解,==比较变量的值是否相等,即变量对应的栈中存放的存放的数值是不是相等的。因为基本类型的数据直接存放在栈中,所以只要值相等,==就返回true。而对于对象来说,栈中存放的是Java对中对象的地址(直接指针访问)或者句柄池中句柄的地址(句柄访问)。所以==比较的是,两边是否为同一个对象(对象的地址是否相同)。

    equals()

    equals方法是Object类的公开方法,具体作用根据类的不同而有所变化。

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

    从源码可以看出,Object类中的equals方法其实就是==。注释上还写明:equals方法表示,一个对象“等于”另一个对象,这个方法对于非null对象具有等价性。
    等价性(限于非null对象):

    • 自反性:x.equals(x)返回true。
    • 对称性:x.equals(y)与y.equals(x)的返回结果应该相同
    • 可传递性:x.equals(y)返回ture,y.equals(z)返回true,那么x.equals(z)也应该返回true。
    • 一致性:只要equals方法中要比较的信息没有修改,那么即使多次调用x.equals(y),返回的结果应该都是相同的。

    重写equals方法时,一般也要重写hashcode方法,保证等价的对象要有相同的哈希码。

        // String类
        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;
        }
    

    在String类中,equals方法被重写了。根据源码,先使用==判断比较的两个对象是否为同一个对象。如果不是的话,再使用instanceof判断要比较的对象是否为String类型。接着比对两个字符串的长度,再比较其字符序列是否相同。

        // AbstractMap类
        public boolean equals(Object o) {
            if (o == this)
                return true;
    
            if (!(o instanceof Map))
                return false;
            Map<?,?> m = (Map<?,?>) o;
            if (m.size() != size())
                return false;
    
            try {
                Iterator<Entry<K,V>> i = entrySet().iterator();
                while (i.hasNext()) {
                    Entry<K,V> e = i.next();
                    K key = e.getKey();
                    V value = e.getValue();
                    if (value == null) {
                        if (!(m.get(key)==null && m.containsKey(key)))
                            return false;
                    } else {
                        if (!value.equals(m.get(key)))
                            return false;
                    }
                }
            } catch (ClassCastException unused) {
                return false;
            } catch (NullPointerException unused) {
                return false;
            }
    
            return true;
        }
    

    在Abstract类中重写的equals方法,同样也是先判断比较的对象是否为同一个,然后用instanceof判断类型,用size方法判断大小。接着遍历被比较的Map实例,如果value为null,那么比较m是否有这个key,并且该key对应的value值也为null。如果value不为null,那么比较两个value存放的对象是否等价。

    hashCode()

        // Object类
        public native int hashCode();
    

    hashCode返回对象的哈希码值,它的一般规约有:

    • 多次调用同一对象时,返回的哈希码值应该相同。
    • 如果两个对象等价(调用equals方法返回true),那么它们的哈希码值一定也相同。
    • 不等价的对象的哈希码值不一定不同。尽量使其不相同。
      等价的对象的哈希码值一定相等,相同哈希码值的对象不一定等价。
        // 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;
        }
    

    String类的哈希码的计算方式是:s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1]。其中s[i]是字符串的第i个字符,n是字符串的长度,^表示取幂。 (空字符串的散列值为零。)

    相关文章

      网友评论

          本文标题:Java:== 、equals()和hashCode()

          本文链接:https://www.haomeiwen.com/subject/fmlesftx.html