关于HashSet的方法contains比较值问题

直接看代码,为什么我直接添加一个String对象contains()返回的是true,添加一个Dog对象的时候就返回false,还有Set不是不能添加一个重复元素,为什么Dog对象可以添加两个,String对象则不能


class Dog{

String color;
public Dog(String s){
    color = s;
}   

}

public class SetAndHashCode {

public static void main(String[] args) {
    HashSet<Dog> dogSet = new HashSet<Dog>();
    boolean resultq;
    dogSet.add(new Dog("we have white"));
    System.out.println("We have " + dogSet.size() + " white dogs!");
    resultq = dogSet.contains(new Dog("we have white"));
    System.out.println(resultq);
       
    HashSet<String> books = new HashSet<String>();    
    //添加一个字符串对象  
    books.add(new String("Struts2权威指南"));  
    books.add(new String("Struts2权威指南"));
    boolean result = books.contains(new String("Struts2权威指南")); 
    System.out.println("We have " + books.size() + " books!");         
    System.out.println(result);          
    //下面输出看到集合只有一个元素  
    System.out.println(books);    
}

}
执行结果是:
**We have 2 white dogs!
false
We have 1 books!
true
[Struts2权威指南]**

阅读 11.6k
3 个回答

这个问题直接看源码。contains源码使用的是HashMap的getNdoe方法

图片描述

判断是否包含另一个对象要同时满足hash相等和内存中是否是同一个对象或者equals方法是否相等。
String对象已经重写了hashCode和equals方法,只要String的value相等,即返回的hashcode相等,equals返回true.
Dog对象没有写hashCode和equals方法,使用的是父类Object的方法,创建不同的对象的hashcode不同,equals返回false,所以不会满足上图源码的if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))条件,所以可以使用color属性重写hashcode和equals方法,调用contains返回true

String对象重写了equeals()和hashCode()方法。
String的hashCode的计算是根据String里面的char数组计算的,char[]数组一样,那么hashCode一样,对于HashSet来说就是同一个元素。
而对于普通对象来说,new一个就是一个与众不同的,hashCode()与地址相关,始终保持不同

Set的特点是去重,key不能重复一定没问题。有一个点,如果进入Set的key是String类型,看看Set都做了些什么,首先对key做了一个hash计算拿到一个hashCode值,Iterator keys做equals比较,如果返回true那么这个key就放不进去了,达到了去重的效果。如果进入Set的key是一个对象呢,都知道new一个对象,他们如果相等那么hashCode一定也相等,equals肯定也是true,可JVM不吃这套,定义了每个new出来的对象都是独一无二的,这就导致了equals 返回false,那么Set可以放下Dog对象,因为你前后放入的是两个Dog对象,而不是一个Dog类。希望可以帮到你,问题的地方,欢迎大神们拍砖指正!

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题