




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
如果函数返回类型不同,子类的同名函数不能继承父类的同名函数 c+ 如果返回值类型是基本数据类型,必须相同,不然编译不通过。如果返回值类型是类类型,可以不相同hashcode方法浅析有许多人学了很长时间的Java,但一直不明白hashCode方法的作用,我来解释一下吧。首先,想要明白hashCode的作用,你必须要先知道Java中的集合。总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。 于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。如果详细讲解哈希算法,那需要更多的文章篇幅,我在这里就不介绍了。初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。 这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。 所以,Java对于eqauls方法和hashCode方法是这样规定的:1、如果两个对象相同,那么它们的hashCode值一定要相同;2、如果两个对象的hashCode相同,它们并不一定相同 上面说的对象相同指的是用eqauls方法比较。 你当然可以不按要求去做了,但你会发现,相同的对象可以出现在Set集合中。同时,增加新元素的效率会大大下降。java中hashcode()和equals()的详解 1. 首先equals()和hashcode()这两个方法都是从object类中继承过来的。 equals()方法在object类中定义如下: public boolean equals(Object obj) return (this = obj); 很明显是对两个对象的地址值进行的比较(即比较引用是否相同)。但是我们必需清楚,当String 、Math、还有Integer、Double。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法。比如在String类中如下: public boolean equals(Object anObject) if (this = anObject) return true; if (anObject instanceof String) String anotherString = (String)anObject; int n = count; if (n = anotherString.count) char v1 = value; char v2 = anotherString.value; int i = offset; int j = anotherString.offset; while (n- != 0) if (v1i+ != v2j+) return false; return true; return false; 很明显,这是进行的内容比较,而已经不再是地址的比较。依次类推Double、Integer、Math。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。当然了基本类型是进行值的比较,这个没有什么好说的。 我们还应该注意,Java语言对equals()的要求如下,这些要求是必须遵循的: 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。 反射性:x.equals(x)必须返回是“true”。 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。 还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。 任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。 以上这五点是重写equals()方法时,必须遵守的准则,如果违反会出现意想不到的结果,请大家一定要遵守。 2. 其次是hashcode() 方法,在object类中定义如下: public native int hashCode(); 说明是一个本地方法,它的实现是根据本地机器相关的。当然我们可以在自己写的类中覆盖hashcode()方法,比如String、Integer、Double。等等这些类都是覆盖了hashcode()方法的。例如在String类中定义的hashcode()方法如下: public int hashCode() int h = hash; if (h = 0) int off = offset; char val = value; int len = count; for (int i = 0; i len; i+) h = 31*h + valoff+; hash = h; return h; 解释一下这个程序(String的API中写到): s0*31(n-1) + s1*31(n-2) + . + sn-1 使用 int 算法,这里 si 是字符串的第 i 个字符,n 是字符串的长度, 表示求幂。(空字符串的哈希码为 0。) 3.这里我们首先要明白一个问题: equals()相等的两个对象,hashcode()一定相等; equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码在生成的时候产生冲突造成的)。 反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。解释下第3点的使用范围,我的理解是在object、String等类中都能使用。在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了;在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时, Hashcode()方法根据String类的重写(第2点里面已经分析了)代码的分析,也可知道hashcode()返回结果也会相等。以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。 4.谈到hashcode()和equals()就不能不说到hashset,hashmap,hashtable中的使用,具体是怎样呢,请看如下分析: Hashset是继承Set接口,Set接口又实现Collection接口,这是层次关系。那么hashset是根据什么原理来存取对象的呢? 在hashset中不允许出现重复对象,元素的位置也是不确定的。在hashset中又是怎样判定元素是否重复的呢?这就是问题的关键所在,经过一下午的查询求证终于获得了一点启示,和大家分享一下,在java的集合中,判断两个对象是否相等的规则是: 1),判断两个对象的hashCode是否相等 如果不相等,认为两个对象也不相等,完毕 如果相等,转入2) (这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低,所以我们这里将其做为必需的。后面会重点讲到这个问题。) 2),判断两个对象用equals运算是否相等 如果不相等,认为两个对象也不相等 如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键) 为什么是两条准则,难道用第一条不行吗?不行,因为前面已经说了,hashcode()相等时,equals()方法也可能不等,所以必须用第2条准则进行限制,才能保证加入的为非重复元素。 比如下面的代码: public static void main(String args) String s1=new String(zhaoxudong); String s2=new String(zhaoxudong); System.out.println(s1=s2);/false System.out.println(s1.equals(s2);/true System.out.println(s1.hashCode();/s1.hashcode()等于s2.hashcode() System.out.println(s2.hashCode(); Set hashset=new HashSet(); hashset.add(s1); hashset.add(s2); /*实质上在添加s1,s2时,运用上面说到的两点准则,可以知道hashset认为s1和s2是相等的,是在添加重复元素,所以让s2覆盖了s1;*/ Iterator it=hashset.iterator(); while(it.hasNext() System.out.println(it.next(); 最后在while循环的时候只打印出了一个”zhaoxudong”。 输出结果为:false true -967303459 -967303459 这是因为String类已经重写了equals()方法和hashcode()方法,所以在根据上面的第1.2条原则判定时,hashset认为它们是相等的对象,进行了重复添加。 但是看下面的程序: import java.util.*; public class HashSetTest 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(); class Student int num; String name; Student(int num,String name) this.num=num; =name; public String toString() return num+:+name; 输出结果为: 1:zhangsan 1:zhangsan 3:wangwu 2:lisi 问题出现了,为什么hashset添加了相等的元素呢,这是不是和hashset的原则违背了呢?回答是:没有 因为在根据hashcode()对两次建立的new Student(1,zhangsan)对象进行比较时,生成的是不同的哈希码值,所以hashset把他当作不同的对象对待了,当然此时的equals()方法返回的值也不等(这个不用解释了吧)。那么为什么会生成不同的哈希码值呢?上面我们在比较s1和s2的时候不是生成了同样的哈希码吗?原因就在于我们自己写的Student类并没有重新自己的hashcode()和equals()方法,所以在比较时,是继承的object类中的hashcode()方法,呵呵,各位还记得object类中的hashcode()方法比较的是什么吧! 它是一个本地方法,比较的是对象的地址(引用地址),使用new方法创建对象,两次生成的当然是不同的对象了(这个大家都能理解吧。),造成的结果就是两个对象的hashcode()返回的值不一样。所以根据第一个准则,hashset会把它们当作不同的对象对待,自然也用不着第二个准则进行判定了。那么怎么解决这个问题呢? 答案是:在Student类中重新hashcode()和equals()方法。 例如: class Student int num; String name; Student(int num,String name) this.num=num; =name; public int hashCode() return num*name.hashCode(); public boolean equals(Object o) Student s=(Student)o; return num=s.num & name.equals(); public String toString() return num+:+name; 根据重写的方法,即便两次调用了new Student(1,zhangsan),我们在获得对象的哈希码时,根据重写的方法hashcode(),获得的哈希码肯定是一样的(这一点应该没有疑问吧)。 当然根据equals()方法我们也可判断是相同的。所以在向hashset集合中添加时把它们当作重复元素看待了。所以运行修改后的程序时,我们会发现运行结果是: 1:zhangsan 3:wangwu 2:lisi 可以看到重复元素的问题已经消除。 关于在hibernate的pojo类中,重新equals()和hashcode()的问题: 1),重点是equals,重写hashCode只是技术要求(为了提高效率) 2),为什么要重写equals呢,因为在java的集合框架中,是通过equals来判断两个对象是否相等的 3),在hibernate中,经常使用set集合来保存相关对象,而set集合是不允许重复的。我们再来谈谈前面提到在向hashset集合中添加元素时,怎样判断对象是否相同的准则,前面说了两条,其实只要重写equals()这一条也可以。 但当hashset中元素比较多时,或者是重写的equals()方法比较复杂时,我们只用equals()方法进行比较判断,效率也会非常低,所以引入了hashcode()这个方法,只是为了提高效率,但是我觉得这是非常有必要的(所以我们在前面以两条准则来进行hashset的元素是否重复的判断)。 比如可以这样写: public int hashCode() return 1;/等价于hashcode无效 这样做的效果就是在比较哈希码的时候不能进行判断,因为每个对象返回的哈希码都是1,每次都必须要经过比较equals()方法后才能进行判断是否重复,这当然会引起效率的大大降低。 我有一个问题,如果像前面提到的在hashset中判断元素是否重复的必要方法是equals()方法(根据网上找到的观点),但是这里并没有涉及到关于哈希表的问题,可是这个集合却叫hashset,这是为什么? 我想,在hashmap,hashtable中的存储操作,依然遵守上面的准则。所以这里不再多说。这些是今天看书,网上查询资料,自己总结出来的,部分代码和语言是引述,但是千真万确是自己总结出来的。有错误之处和不详细不清楚的地方还请大家指出,我也是初学者,所以难免会有错误的地方,希望大家共同讨论。 1. =是用来比较两个变量(基本类型和对象类型)的值是否相等的, 如果两个变量是基本类型的,那很容易,直接比较值就可以了。如果两个变量是对象类型的,那么它还是比较值,只是它比较的是这两个对象在栈中的引用(即地址)。 对象是放在堆中的,栈中存放的是对象的引用(地址)。由此可见=是对栈中的值进行比较的。如果要比较堆中对象的内容是否相同,那么就要重写equals方法了。 2. Object类中的equals方法就是用=来比较的,所以如果没有重写equals方法,equals和=是等价的。 通常我们会重写equals方法,让equals比较两个对象的内容,而不是比较对象的引用(地址)因为往往我们觉得比较对象的内容是否相同比比较对象的引用(地址)更有意义。 3. Object类中的hashCode是返回对象在内存中地址转换成的一个int值(可以就当做地址看)。所以如果没有重写hashCode方法,任何对象的hashCode都是不相等的。通常在集合类的时候需要重写hashCode方法和equals方法,因为如果需要给集合类(比如:HashSet)添加对象,那么在添加之前需要查看给集合里是否已经有了该对象,比较好的方式就是用hashCode。 4. 注意的是String、Integer、Boolean、Double等这些类都重写了equals和hashCode方法,这两个方法是根据对象的内容来比较和计算hashCode的。(详细可以查看jdk下的String.java源代码),所以只要对象的基本类型值相同,那么hashcode就一定相同。 5. equals()相等的两个对象,hashcode()一般是相等的,最好在重写equals()方法时,重写hashcode()方法; equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。 反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。在object类中,hashcode()方法是本地方法,返回的是对象的引用(地址值),而object类中的equals()方法比较的也是两个对象的引用(地址值),如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了。 以下是测试代码。 Java代码 1. publicclassEquals_HashCode 2. publicstaticvoidmain(Stringargs) 3. Stringa=newString(str); 4. Stringb=newString(str); 5. System.out.println(a=b); 6. System.out.println(a.equals(b); 7. System.out.println(a.hashCode(); 8. System.out.println(b.hashCode(); 9. /输出falsetrue114225114225 10. classA 11. Stringstr; 12. inti; 13. publicA(Stringstr,inti) 14. super(); 15. this.str=str; 16. this.i=i; 17. 18. 19. AaA=newA(str,1); 20. AbA=newA(str,1); 21. System.out.println(aA=bA); 22. System.out.println(aA.equals(bA); 23. System.out.println(aA.hashCode(); 24. System.out.println(bA.hashCode(); 25. /输出falsefalse641387521174459 26. classB 27. Stringstr; 28. publicB(Stringstr) 29. this.str=str; 30. 31. 32. BaB=newB(str); 33. BbB=newB(str); 34. System.out.println(aB=bB); 35. System.out.println(aB.equals(bB); 36. System.out.println(aB.hashCode(); 37. System.out.println(bB.hashCode(); 38. /输出falsefalse82757417510567 39. classC 40. inti; 41. publicC(inti) 42. this.i=i; 43. 44. 45. CaC=newC(1); 46. CbC=newC(1); 47. System.out.println(aC=bC); 48. System.out.println(aC.equals(bC); 49. System.out.println(aC.hashCode(); 50. System.out.println(bC.hashCode(); 51. /输出falsefalse2774445928737396 52. 53. 54. 55. java中equal和=的比较 java中equals方法和“=”的区别:equals 方法是 java.lang.Object 类的方法。有两种用法说明:(1)对于字符串变量来说,使用“=”和“equals()”方法比较字符串时,其比较方法不同。“=”比较两个变量本身的值,即两个对象在内存中的首地址。“equals()”比较字符串中所包含的内容是否相同。比如:String s1,s2,s3 = abc, s4 =abc ;s1 = new String(abc);s2 = new String(abc);那么:s1=s2 是 false /两个变量的内存地址不一样,也就是说它们指向的对象不 一样,故不相等。s1.equals(s2) 是 true /两个变量的所包含的内容是abc,故相等。注意(1):如果: StringBuffer s1 = new StringBuffer(a);StringBuffer s2 = new StringBuffer(a);结果: s1.equals(s2) /是false解释:StringBuffer类中没有重新定义equals这个方法,因此这个方法就来自Object类,而Object类中的equals方法是用来比较“地址”的,所以等于false.注意(2):对于s3和s4来说,有一点不一样要引起注意,由于s3和s4是两个字符串常量所生成的变量,其中所存放的内存地址是相等的,所以s3=s4是true(即使没有s3=s4这样一个赋值语句)(2)对于非字符串变量来说,=和equals方法的作用是相同的都是用来比较其对象在堆内存的首地址,即用来比较两个引用变量是否指向同一个对象。比如:class AA obj1 = new A();A obj2 = new A();那么:obj1=obj2是falseobj1.equals(obj2)是false但是如加上这样一句:obj1=obj2;那么 obj1=obj2 是trueobj1.equals(obj2) 是true总之:equals方法对于字符串来说是比较内容的,而对于非字符串来说是比较其指向的对象是否相同的。= 比较符也是比较指向的对象是否相同的也就是对象在对内存中的的首地址。String类中重新定义了equals这个方法,而且比较的是值,而不是地址。所以是true。关于equals与=的区别从以下几个方面来说:(1)如果是基本类型比较,那么只能用=来比较,不能用equals比如:public class TestEquals public static void main(String args)int a = 3;int b = 4;int c = 3;System.out.println(a = b);/结果是falseSystem.out.println(a = c);/结果是trueSystem.out.println(a.equals(c);/错误,编译不能通过,equals方法/不能运用与基本类型的比较(2)对于基本类型的包装类型,比如Boolean、Character、Byte、Shot、Integer、Long、Float、Double等的引用变量,=是比较地址的,而equals是比较内容的。比如:public class TestEquals public static void main(String args) Integer n1 = new Integer(30);Integer n2 = new Integer(30);Integer n3 = new Integer(31);System.out.println(n1 = n2);/结果是false 两个不同的Integer对象,故其地址不同,System.out.println(n1 = n3);/那么不管是new Integer(30)还是new Integer(31) 结果都显示falseSystem.out.println(n1.equals(n2);/结果是true 根据jdk文档中的说明,n1与n2指向的对象中的内容是相等的,都是30,故equals比较后结果是trueSystem.out.println(n1.equals(n3);/结果是false 因对象内容不一样,一个是30一个是31这是Integer的实例,如果是其他的比如Double、Character、Float等也一样。(3)注意:对于String(字符串)、StringBuffer(线程安全的可变字符序列)、StringBuilder(可变字符序列)这三个类作进一步的说明。(a)首先,介绍String的用法,请看下面的实例:public class TestEquals public static void main(String args) String s1 = 123;String s2 = 123;String s3 = abc;String s4 = new String(123
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 宝鸡仿古工程施工方案
- 全市校园消防安全教育鄂州市
- 人工气候室维修工程精细化施工设计方案
- 给水工程水质监测及管理方案
- 校园欺凌安全教育海报
- 政治理论考试题目及答案
- 政府评审专家考试题型及答案
- 城乡供水服务质量提升优化方案
- PLC项目实施进度管理方案
- 文学阅读类活动策划方案
- 职业技能大赛-电工职业技能竞赛理论题库(附参考答案)
- 基坑工程质量保证措施
- DL∕T 514-2017 电除尘器 标准
- 人教版六年级英语上册《全册》完整版
- 2023人教版九年级语文上册 第一单元主题阅读 课件
- 媒介素养概论 课件 刘勇 第0-4章 绪论、媒介素养-新闻评论
- 美慧树课件教材培训
- 2023年北京市中考物理试卷(解析版)
- 幼儿园学生近视防控工作领导小组及岗位职责
- 沙盘游戏在自闭症中的运用课件
- 青稞栽培管理培训课件
评论
0/150
提交评论