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

在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. 1.httpClient和ScrollView

    1 在服务器端使用sqllite编写数据库 常见命令是:sqlite3 tank.db 进入之后创建表: create table tscore ( id integer primary key au ...

  2. Android自定义处理崩溃异常

    用过安卓手机的用户以及安卓开发者们会时长碰到程序异常退出的情况,普通用户遇到这种情况,肯定非常恼火,甚至会骂一生垃圾软件,然后卸载掉.那么开发者们在开发过程中遇到这种情况给怎么办呢,当然,你不可能世界 ...

  3. 关于查找iOS中App路径时所要注意的一个问题

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...

  4. iOS开发之WKWebView代替UIWebView

    前言 Xcode8发布以后,编译器开始不支持IOS7,所以很多应用在适配IOS10之后都不在适配IOS7了,其中包括了很多大公司,网易新闻,滴滴出行等.因此,我们公司的应用也打算淘汰IOS7. 支持到 ...

  5. Android项目开发填坑记-9patchPng报错

    如果阅读体验不佳,请使用–> Github版 背景 之前写了一篇文章Android必知必会–NinePatch图片制作详细介绍了Android 9Patch图片的制作和一些Demo展示,这次说明 ...

  6. 两种配置大数据环境的方法Ambari以及hadoop源代码安装的步骤

    1.Ambari安装 Ambari & HDP(Hortonworks Data Platform) ********************************************* ...

  7. GDAL使用插件方式编译HDF4、HDF5以及NetCDF的bug修改

    GDAL库中提供了很方便的插件机制来扩展支持的数据格式,比如HDF4.HDF5.NetCDF.FileGDB.Postgre.Oralce等等.都可以通过插件的方式来使得GDAL支持相应的格式.最近将 ...

  8. 控制成本,控制成本知识点,挣值和实际成本、EAC,ETC.TCPI解析表

  9. ubuntu常用文件搜索命令

    1.find find [搜索路径] [搜索关键字] 比如查找/test中文件名为t5.tmp的文件: 查找根目录下大于100M的文件 注意,这里的204800单位是块,1块=512字节 在根目录下查 ...

  10. 初次见面 你好EF

    EF(yif),第一次听到这个名字的时候,以为是一个帅帅的魔术师,在小编的傻傻的梦想里,就是有一天,有一个魔术师站在小编面前,变出一大捧的玫瑰花,然后,然后不要钱`(*∩_∩*)′,然而在我们的编程世 ...