java中的hashcode、equals和toString方法都是基类Object的方法。
首先说说toString方法,简单的总结了下API说明就是:返回该对象的字符串表示,信息应该是简明但易于读懂的信息表达式,一般来说大部分的常见类都会重写这个方法。比如Collection会重写的该方法就会在集合前后加上[ ]中间的元素中间会加上。但是如果没有重写的话Object的默认的toString方法是返回:getClass().getName() + '@' + Integer.toHexString(hashCode()) 即这个类的实例的类名+“@”+hashcode的16进制表示。这里就引进了hashcode的概念了。
hashcode方法是返回哈希码的一个方法,这里哈希码可以认为是地址的概念,用处是在某些时候加快哈希表的性能。因此在涉及到哈希表的操作的时候就可能设计到hashcode的调用。
equals方法是比较两个类,默认的效果是和==一样的,即比较引用(地址)看是不是同一个元素,但是因为大部分情况下比较两个元素是不是同一个元素是没有意义的所以会重写这个方法。比如:String会重写为判断两个字符串是不是相同,而自定义的复杂类更要自己定义比较的规则。
而在集合的hashset的时候,因为set中不会存储相同的元素,而是否相同也是你判断的。为了方便,内部的规则是先判断hashcode,如果hashcode不同的话就直接存入。如果hashcode相同的再判断equals是不是true。我们针对例子分析。
1 package TestCollection;
2
3 import java.util.Collection;
4 import java.util.HashSet;
5 import java.util.LinkedList;
6 import java.util.TreeSet;
7
8 import pack.SOP;
9
10 public class TestCollection {
11
12 /**
13 * @param args
14 */
15 public static void main(String[] args) {
16 // TODO Auto-generated method stub
17 Collection c = new HashSet();
18 c.add(new Integer(100));
19 c.add("abcdefg");
20 c.add("abcdefg");
21 c.add(new Cat("米米",3));
22 c.add(new Cat("米米",3));
23 SOP.sop(c.size());
24 SOP.sop("==================");
25 SOP.sop(c);
26
27 }
28
29 }
30
31 class Cat {
32 String name;
33 int age;
34 Cat(){
35
36 }
37 Cat(String name,int age){
38 this.name = name;
39 this.age =age;
40 }
41 public boolean equals(Object obj){
42 if(obj instanceof Cat){
43 Cat c = (Cat)obj;
44 SOP.sop("==================");
45 return false;
46 // return (this.name.equals(c.name))&&(this.age==c.age) ;
47 }
48 return super.equals(obj);
49
50 }
51 public int hashCode() {
52 //return name.hashCode();
53 return 0x68888;
54 }
55 /*public String toString() {
56 //return "是这样吗";
57 return "name :"+name+"age :"+age;
58 }*/
59 }
向hashset中添加元素,hashset有个规则是不存储相同的元素,而相同与否是由各自的规则判断的,比如插入字符串的时候,String的equals规则是只要指向的内容相同就true。所以两个相同的“abcdefg”就只有一个。
接下来就是插入自定义的类了。
首先需要自定义toString方法让print的时候按照自己的需求显示。
重写equals方法和hashcode方法进行是不是相同元素的判断。
然后做如下的测试证明原理的正确性:
首先不写hashcode方法,则即使equals判断了内容规则了,但是set中会存在相同显示的两个元素,这是因为虚拟机会先判断hashCode方法,因为没有写hashCode方法的话会继承父类的hashCode方法,所以两个对象的hashcode值不一样,所以这里是不会判断equals方法就直接认定两个元素是不一样的,即使你“看上去是一样的”。
然后重写了hashcode方法,如果定义了固定了int值,则Object的默认的toString会把你定义的hashcode值显示出来。
然后如果有了相同的hashcode的话就接着判断equals方法,如果自己定义让返回的值始终是false的话,也会两个都显示出来,因为虚拟机会认为他们是两个元素。只有hashcode和equals都一样的话,才会认为是两个相同的元素。插入的时候,只插入一个。
最后得出结论:虚拟机判断两个元素是不是相同首先判断两个元素的hashcode,如果hashcode不同,则直接认为不同;如果hashcode相同,再判断equals方法是不是相同,如果equals不同,则两个元素不同,如果equals相同,则才会最终认为元素相同。因为很多系统的类实现了这些方法,因此我们在自定义的时候可以拿来调用系统类的这些方法。