理解Set里面为何不能有重复对象_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 理解Set里面为何不能有重复对象

理解Set里面为何不能有重复对象

 2010/11/17 22:48:47  My*Love  http://chaozhichen.javaeye.com  我要评论(0)
  • 摘要:最近到处参加笔试,也没好好的去研究这些题目,但我发现好多笔试里面,String真的差不多必考,然后就是==与equals()的用法,基本屡试不爽。昨天不知怎么又搞到equals()去了,equals()方法是Object里面的一个方法,里面实现很简单:publicbooleanequals(Objectobj){return(this==obj);}其实里面比较的是两个对象的引用是否相同(即对象的地址值是否相同),但像String
  • 标签:Set不能有重复对象
   最近到处参加笔试,也没好好的去研究这些题目,但我发现好多笔试里面,String真的差不多必考,然后就是==与equals()的用法,基本屡试不爽。
   昨天不知怎么又搞到equals()去了,equals()方法是Object里面的一个方法,里面实现很简单:
 public boolean equals(Object obj) {
	         return (this == obj);
              }

其实里面比较的是两个对象的引用是否相同(即对象的地址值是否相同),但像String、Integer等这些引用数据的类型里已经重写了Object里面的equals()方法,如String中的equals()方法内容:
 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 (v1[i++] != v2[j++])
			return false;
		}
		return true;
	    }
	}
	return false;
    }

第一个if比较引用是否相同,第二个if是比较字符串的值是否全相等,可以说这些重写后的equals()方法其实比较的是对象的内容是否相同。
     其实也可以想到Set怎么实现的了,它肯定是在你add一个对象的时候,调用了equals方法,看里面有没有相同对象。下面来看一个示例:
Student类
public class Student {
	private int age;
	private String name;

	public Student(int age, String name) {
		this.age = age;
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String toString() {
		return age + " " + name;
	}
}

测试一下:
  
   public static void main(String args[]) {
		
		Set<Student> set = new HashSet<Student>();
		set.add(new Student(1, "czc"));
		set.add(new Student(2, "yqq"));
		set.add(new Student(3, "lz"));
		set.add(new Student(1, "czc"));

		Iterator<Student> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
   

输出结果为:
          2 yqq
         1 czc
         3 lz
         1 czc
为什么会有两个相同的对象?
      查看HashSet的add方法,你会发现它是把对象放到一个HashMap里面,HashMap里面的put方法实现如下:
 public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
           if (e.hash == hash && ((k = e.key) == key || key.equals(k))){
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

从红色那一行可以看出,它判断是不是同一对象,还用到了一个hash值,即对象的hashCode值。
     hashCode()方法是Object里面的一个本地(native,实现看不到,应该是C/C++去实现的,具体也不懂)方法,像String、Integer等类都重写了hashCode方法,不同类的实现都用到了不同算法,感觉还是Integer最简单,直接就是输入的那个数。
     现在应该知道为什么输出两个相同的对象了吧,因为Student是自己写的一个类,用的是Object里面的equals()方法,知道Object里面方法的实现吧,其实就是比较引用是否相同,显然new出来的是两个不同的东西,所以Set认为是两上不同对象,都放进去了。
    可能有人会发现,为什么定义两个相同字符串对象,放到Set里面去,打印时只输出了一个对象,这是因为String它里面重写了hashCode()与equals()方法,所以解决刚才的问题就很简单了,我们只要在Student中重写hashCode()与equals()就可以了。在Student中加入如下代码:
        /**
	 * 重写hashcode方法
	 *
	 * @return
	 */
	 public int hashCode() {
	 return age * name.hashCode();
	 }
		
		
	 /**
	 * 重写equals方法
	 */
	 public boolean equals(Object obj) {
	 Student s = (Student) obj;
	 return age == s.age && name.equals(s.name);
	 }

最后测试结果是:
      2 yqq
     3 lz
     1 czc
     最后总结下equals()与对象的hash值的关系:
         a. equals()相等的两个对象,hashcode()一定相等;
        b. equals()方法不相等的两个对象,hashcode()有可能相等
如:Integer s1=new Integer(97);
   String s2 = new String("a");
                  它们是不等的,但它们的hashcode值都为97
        c.反过来,hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()不定相等,如上所示的例子
    
      对于原理性的东西,我也有很多不明白的地方,文章所写有些全为个人见解,难免会有理解偏差之处,希望高手不吝赐教。
  • 相关文章
发表评论
用户名: 匿名