关于hashCode与equals
首先我得说明,在我们自己写得类中你可以复写这两个方法,此时从语法的角度来说,他们没关系。
在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的更多相关文章
- 对hashcode、equals的理解
1.首先hashcode和equals都是java每个对象都存在的方法,因为他们两是Object的方法. 2.hashcode方法默认返回的是该对象内存地址的哈希码,然而你会发现,Object类中没有 ...
- java中hashcode()和equals()的详解
今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36). 1. 首先equals()和hashc ...
- Java hashCode() 和 equals()的若干问题
原文:http://www.cnblogs.com/skywang12345/p/3324958.html 本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() ...
- java中的hashcode()和equals()
equals()和hashcode()都继承自object类. equals() equals()方法在object类中定义如下: public boolean equals(Object obj) ...
- Java hashCode() 和 equals()的若干问题解答
本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() 与 == 的区别是什么? 3 hashCode() 的作用是什么? 4 hashCode() 和 equa ...
- 【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap
参考的优秀文章: <Java编程思想>第四版 <Effective Java>第二版 Map接口是映射表的结构,维护键对象与值对象的对应关系,称键值对. > hashco ...
- 【Java】hashcode()和equals()
大家知道,在集合中判断集合中的两个元素是否相同,依赖的是hashcode()和equals()两个方法. > 一个简单的实验 public class Teacher { private Int ...
- 用HashSet的add方法谈hashcode和equals方法重写
本文主要通过用HashSet的add方法讲一下hashCode和equals方法重写.错误的地方望指正. 1.了解HashSet的add方法 了解一个方法的好办法是看源码,所以先看源码 private ...
- Maintainable HashCode and Equals Using Apache Commons
Java hashCode and equals methods can be tricky to implement correctly. Fortunately, all majors IDEs ...
- Java中hashcode,equals和==
hashcode方法返回该对象的哈希码值. hashCode()方法可以用来来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的位置,Map在搜索一个对象的时候先通过has ...
随机推荐
- [安全]Back_Track_5 vm 版安装和使用
下载安装 下载使用国内的镜像 http://mirrors.ustc.edu.cn/kali-images/kali-1.0.9/ 我这里是vm9.0 下载之后解压,然后打开vm,然后 文件--&g ...
- CSDN发表文章后老是待审核的原因
最近开始在csdn上写文章,发现老是文章被 待审核 ,于是便在网上搜集了下网友们的反馈,最后做出以下的整理. 1.CSDN检测到文章中的链接大于5,就会将文章列为"待审核",这个其 ...
- java虚拟机 jvm 栈数据区
java栈帧还是需要一些数据支持常量池的解析.正常方法的返回和异常的处理.大部分的java字节码指令需要进行常量池的访问,在栈帧数据区中保存着访问常量池的指针,方便程序访问java常量池.如下图所示: ...
- 高通msm8994性能及温度监测脚本
[plain] view plain copystartTime=$(date +%Y-%m-%d-%H-%M-%S) pathName="/data/cpu_logs" fi ...
- Ubuntu下安装GTK环境
要生成C图形界面的程序,得安装GTK环境 安装GTK环境只要安装一个gnome-core-devel就可以了,里面集成了很多其他的包.除此之外还要转一些其他的 东西,如libglib2.0 ...
- Linux之mailx的使用
mailx是UNIX系统上用来处理邮件的工具,使用它可以发送,读取邮件.下面看看如何使用它来发送邮件. 发送格式 mailx -s subject user@xxx.com < message_ ...
- 【Unity Shaders】使用CgInclude让你的Shader模块化——使用#define指令创建Shader
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- iOS中 WGAFN_网络监控 技术分享
需要用到第三方AFNetworking/SVProgressHUD 没有的可以关注我微博私信我.http://weibo.com/hanjunqiang AppDelegate.m #import & ...
- pig加载两个不同字段个数的文件?load file with different items(f1有42列,f2有43列读到一个对象中)
我文章提到,加载一个文件的部分列是可行.两列,你只读一列,没问题. 但是,两个文件,f1和f2,f1有42列,f2有43列,同时加载到一个流对象,如何? 答:成功加载.但是无结构(schema unk ...
- Dynamics CRM EntityCollection 根据实体中的某个字段为依据去除重复数据
CRM中通过QueryExpression查询出了一个EntityCollection集,但有时会存在重复数据,QueryExpression中有个属性distinct,只要设置为true就能过滤 ...