首先我得说明,在我们自己写得类中你可以复写这两个方法,此时从语法的角度来说,他们没关系。

在object中

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

两个准则

在java集合中

判定两个对象是否相等需要以下两步;

1 hashCode的值是否相等,

  如果不相等,那么不用说,两个对象肯定不相等;如果hashCode的值相等,那么看第二步;

2 equals的值是否相等;

  如果equals的值相等,那么两个对象相等;

  若是equals的值不相等,那么两个对象不相等;

(我们可以看到,equals起最后的作用)

那就有一个问题了,既然equals起最后的作用我们在集合类中判断两个对象是否相等的时候,就直接调用equals即可,为什么还有hashcode呢?

因为有的时候equals方法比较复杂,我们如果通过hashcode方法已经说明两个对象不相等了就可以不用调用equals了

hashCode是个本地方法,返回的结果是对对象存储位置的一系列复杂运算;

而equals就是单纯的比较两个对象的地址值是否相等;

看到这里就存在几个准则

如果equals相等,那么hashCode一定相等;  地址值已经相等了,再怎么计算它都是相等的

如果hashCode相等了,equals不一定相等;  4%3=1  1%3=1 看到了吧,不同的值经过相同的运算法则,有可能取得相同的值

代码说明

首先我们看看字符串的equals与hashCode

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

在读hashCode方法的注释的时候我一直不明白

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]         //n代码字符串长度  ^代码乘方或者说幂

  for (int i = 0; i < value.length; i++) {

                h = 31 * h + val[i];

            }

从数学上说,这两个有什么关系

后来我验证了一下,两种方法返回的int值是一样的 为什么?不明觉厉!



     下面这个例子的结果我已经写到注释里了

        String s1=new String("zhaoxudong");
        String s2=new String("zhaoxudong");
        String s3="zhaoxudong";
        String s4="zhaoxudong";
        System.out.println(s1==s2);      //两个new出来的对象 s1 s2里面放的是两个不同对象的地址 自然不相等
        System.out.println(s1==s3);         //false 一个指向堆内存 一个指向常量池
        System.out.println(s3==s4);      //true 都在常量池中
        System.out.println("##### ");
        System.out.println(s1.equals(s2));//true
        System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode()等于s3.hashcode()
        System.out.println(s2.hashCode());
        System.out.println(s3.hashCode());

        Set hashset=new HashSet();
        hashset.add(s1);
        hashset.add(s2);
        Iterator it=hashset.iterator();
        while(it.hasNext())
            System.out.println(it.next());  //只打印出一个

再看这个

import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;

public class hashCode
{
    public static void main(String[] args)
    {

        HashSet hs=new HashSet();
        hs.add(new Student(1,"zhangsan"));
        hs.add(new Student(2,"lisi"));
        hs.add(new Student(3,"wangwu"));
        hs.add(new Student(1,"zhangsan"));

        Iterator it=hs.iterator();
        while(it.hasNext())
            System.out.println(it.next());
      }
}
public class Student
   {
     int num;
     String name;
     Student(int num,String name)
                {
                this.num=num;
                 this.name=name;
                 }
              public String toString()
                {
                    return num+":"+name;
                 }
   }   

运行结果

1:zhangsan

3:wangwu

1:zhangsan

2:lisi

两个张三?

因为,hash的add方法在加入新元素的时候,先找Student的hashCode方法,结果没有,那就调用object的hashCode方法,两个zhangsan都是new出来的,自然不是一个对象喽,所以就加进去了!

怎么改?

给stuend类中加入以下两个方法

public int hashCode()
{
            return num*name.hashCode();
}
public boolean equals(Object o)
{
            Student s=(Student)o;
            return num==s.num && name.equals(s.name);
} 

但是,大家得记住,equals相等,hashcode就一定相等这个准则,所以两个方法不要乱写!

改完之后,就只有一个zhangsan了。

参考资料

http://www.iteye.com/topic/257191

关于hashCode与equals的更多相关文章

  1. 对hashcode、equals的理解

    1.首先hashcode和equals都是java每个对象都存在的方法,因为他们两是Object的方法. 2.hashcode方法默认返回的是该对象内存地址的哈希码,然而你会发现,Object类中没有 ...

  2. java中hashcode()和equals()的详解

    今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36). 1. 首先equals()和hashc ...

  3. Java hashCode() 和 equals()的若干问题

    原文:http://www.cnblogs.com/skywang12345/p/3324958.html 本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() ...

  4. java中的hashcode()和equals()

    equals()和hashcode()都继承自object类. equals() equals()方法在object类中定义如下: public boolean equals(Object obj) ...

  5. Java hashCode() 和 equals()的若干问题解答

    本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() 与 == 的区别是什么? 3 hashCode() 的作用是什么? 4 hashCode() 和 equa ...

  6. 【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap

    参考的优秀文章: <Java编程思想>第四版 <Effective Java>第二版 Map接口是映射表的结构,维护键对象与值对象的对应关系,称键值对. > hashco ...

  7. 【Java】hashcode()和equals()

    大家知道,在集合中判断集合中的两个元素是否相同,依赖的是hashcode()和equals()两个方法. > 一个简单的实验 public class Teacher { private Int ...

  8. 用HashSet的add方法谈hashcode和equals方法重写

    本文主要通过用HashSet的add方法讲一下hashCode和equals方法重写.错误的地方望指正. 1.了解HashSet的add方法 了解一个方法的好办法是看源码,所以先看源码 private ...

  9. Maintainable HashCode and Equals Using Apache Commons

    Java hashCode and equals methods can be tricky to implement correctly. Fortunately, all majors IDEs ...

  10. Java中hashcode,equals和==

    hashcode方法返回该对象的哈希码值. hashCode()方法可以用来来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的位置,Map在搜索一个对象的时候先通过has ...

随机推荐

  1. Apache shiro集群实现 (五)分布式集群系统下的高可用session解决方案

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  2. Apache shiro集群实现 (三)shiro身份认证(Shiro Authentication)

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  3. 反射 学习笔记之Class类的使用

    1  java世界中万事万物皆对象,除了2个特殊情况 int float等这些基本数据类型,(但是也都有Integer和Float等封装类做了弥补) java staic定义的,它不是属于对象的,而是 ...

  4. Android开发艺术探索笔记——第一章:Activity的生命周期和启动模式

    Android开发艺术探索笔记--第一章:Activity的生命周期和启动模式 怀着无比崇敬的心情翻开了这本书,路漫漫其修远兮,程序人生,为自己加油! 一.序 作为这本书的第一章,主席还是把Activ ...

  5. 用Maven打包成EAR部署JBoss

    基于原理的架构里面,考虑这次升级版本,可谓是一步一个脚印的向上走啊,可以说步步为坎,别人的知识,和自己的知识,相差很多啊,什么都懂点,但是具体没有使用,就理解不深刻了,心有余而力不足,所以一切我们自己 ...

  6. linux中exec和xargs命令的区别和优劣分析

    find的exec及ok命令 exec命令的格式为: exec command {} \; exec后面跟着的是操作命令,然后跟着{}表示每一个参数,然后空格,然后"\;".{}之 ...

  7. 设置TextView显示的文字可以复制

    设置TextView显示的文字可以复制 效果图 在xml中设置 <TextView android:layout_width="wrap_content" android:l ...

  8. Dynamics CRM2016 站点地图Bug之KnowledgeArticle不显示

    在CRM2016中对知识库功能进行了加强,新加入了KnowledgeArticle的实体,但在学习的过程中发现了微软的一个bug 下图是我在最新的2016online的版本上看到的service下的s ...

  9. Druid VS Antlr4

    DRUID VS ANTLR4 测试方法 环境:x86_64,eclipse kepler,jdk 6 测试对象:antlr v4,druid手写sql parser模块 测试过程:分别采用单线程.多 ...

  10. 随机采样和随机模拟:吉布斯采样Gibbs Sampling实现文档分类

    http://blog.csdn.net/pipisorry/article/details/51525308 吉布斯采样的实现问题 本文主要说明如何通过吉布斯采样进行文档分类(聚类),当然更复杂的实 ...