众所周之,String 、Math、还有Integer、Double。。。。等这些封装类重写了Object中的equals()方法,让它不再比较句柄(引用),而是比较对象中实际包含的整数的值,即比较的是内容。 package holding; import java.util.*; import typeinfo.pets.*; import static net.mindview.util.Print.*; public class MapOfList { public static Map<String,Integer> maptest = new HashMap<String,Integer>(); static { maptest.put("a", new Integer(123)); maptest.put("a", new Integer(312)); maptest.put("b", new Integer(111)); maptest.put("c", new Integer(123)); } public static void main(String[] args) { print("key: " + maptest.keySet()); print("value: " + maptest.values()); for(String s : maptest.keySet()) { print(s + " has: "); print(maptest.get(s)); } } }
结果:
value: [111, 123, 312] b has: 111 c has: 123 a has: 312
没有重复 印证了上面的话一些封装类比较的是内容
而Object的equals()方法比较的是地址值。 同样看个例子 我们自定义类型
package holding; import java.util.*; import typeinfo.pets.*; import static net.mindview.util.Print.*; public class MapOfList { public static Map<Person,List<? extends Pet>> petPeople = new HashMap<Person,List<? extends Pet>>(); static { petPeople.put(new Person("Dawn"), Arrays.asList(new Cymric("Molly"), new Mutt("Spot"))); petPeople.put(new Person("Kate"), Arrays.asList(new Cat("Shackleton"),new Cat("Elsie May"),new Dog("Margrett"))); petPeople.put(new Person("Marilyn"), Arrays.asList(new Pug("Louie aka"),new Cat("Stanford"),new Cat("Pinkola"))); petPeople.put(new Person("Luke"), Arrays.asList(new Rat("Fuzzy"),new Rat("Fuzzy"))); petPeople.put(new Person("Luke"), Arrays.asList(new Rat("Fuzzy"),new Rat("Fuzzy"))); petPeople.put(new Person("Isaac"), Arrays.asList(new Rat("Freckly"))); } public static void main(String[] args) { print("People: "+petPeople.keySet()); print("Pets: "+petPeople.values()); for(Person person : petPeople.keySet()) { print(person + " has: "); for(Pet pet : petPeople.get(person)) { print(" " + pet); } } } } 结果
People: [Person Marilyn, Person Luke, Person Luke, Person Kate] Pets: [[Pug Louie aka, Cat Stanford, Cat Pinkola], [Rat Fuzzy, Rat Fuzzy], [Rat Fuzzy, Rat Fuzzy], [Cat Shackleton, Cat Elsie May, Dog Margrett]] Person Marilyn has: Pug Louie aka Cat Stanford Cat Pinkola Person Luke has: Rat Fuzzy Rat Fuzzy Person Luke has: Rat Fuzzy Rat Fuzzy Person Kate has: Cat Shackleton Cat Elsie May Dog Margrett
比较的是地址,出现了重复。
一般来说,如果你要把一个类的对象放入容器中,那么通常要为其重写equals()方法,让他们比较地址值而不是内容值。特别地,如果要把你的类的对象放入散列中,那么还要重写hashCode()方法;要放到有序容器中,还要重写compareTo()方法。
在java的集合中,判断两个对象是否相等的规则是: 首先,判断两个对象的hashCode是否相等 如果不相等,认为两个对象也不相等 如果相等,则判断两个对象用equals运算是否相等 如果不相等,认为两个对象也不相等 如果相等,认为两个对象相等
看下面的程序: 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; this.name=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; this.name=name; } public int hashCode() { return num*name.hashCode(); } public boolean equals(Object o) { Student s=(Student)o; return num==s.num && name.equals(s.name); } public String toString() { return num+":"+name; } } 根据重写的方法,即便两次调用了new Student(1,"zhangsan"),我们在获得对象的哈希码时,根据重写的方法hashcode(),获得的哈希码肯定是一样的(这一点应该没有疑问吧)。 当然根据equals()方法我们也可判断是相同的。所以在向hashset集合中添加时把它们当作重复元素看待了。所以运行修改后的程序时,我们会发现运行结果是: 1:zhangsan 3:wangwu 2:lisi 可以看到重复元素的问题已经消除。