Set集合中有TreeSet和HashSet....里面添加的对象不能重复....但是奇怪的是我在HashSet中添加2个相同对象,竟然都打印了出来.:代码见下:import java.util.*;public class HashSetTest { public static void main(String[] args) {
  HashSet hs = new HashSet();  hs.add(new WrappedString("aardvark"));
  hs.add(new WrappedString("aardvark"));  //System.out.println(hs.size());   for (Iterator it = hs.iterator(); it.hasNext();) {
   System.out.println(it.next());
  }
 }
}class WrappedString {
 String s; public WrappedString(String s) {
  this.s = s;
 } public int hashCode() {
  return s.hashCode();
 } public boolean equals(Object o) {
  WrappedString ws = (WrappedString)o; //强转
  
  //另一种可行方法,暂时注释它
//  if (s == o)
//   return true;
//  if (!(o instanceof WrappedString))  //WrappendString 是不是 o 的实例
//   return false;
//  
//  if (s.equals(ws.s)) {
//   return true;
//  } else {
//   return false;
//  }
  
  return s == ws.s &&s.equals(ws.s);
  
 } public String toString() {
  return s;
 }}我发现当添加的是基础数据类型.如Integer.Double等HashSet不会重复,但是一旦添加String 等引用数据类型或对象时它会打印重复对象....当然我重写了hashCode()和equals后就正常了...在这里我想问的是 为什么要重写那2个方法...为什么TreeSet不重写打印就是正常的呢.如果说是因为我自定义的类没有覆盖那2个方法,但是String 类型.应该重写了那2个方法的哦.还有即使是我自定义的对象.它应该也是一个Object,应该重写了那2个方法的啊...为什么要自己手动的在HashSet中重写那2个方法才会完全正确呢....希望高手 老师些  能给一个详细的解答

解决方案 »

  1.   

    treeset相对于hashset来说是有顺序的其他参考effective java
      

  2.   

    1.是不是加上了,你可以通过size()来判断。
    你add两次,如果size是2,则说明加上了,是1则说明没有加上。2.是不是同一个对象,不可主观臆测,要看那些关于equal等方法的说明,关于hashCode方法的说明。
    你这里分明是两个对象,而不是一个的。
      

  3.   

    加2个基础数据类型.如add(new Integer(2));add(new Integer(2));这样写它不会重复..关键怪就怪在 String 等引用类型就会重复...必须重写
    equals和hashCode方法...但是真的很不明白为什么要重写..而其他的对象添进去却不重写
      

  4.   

    Size确实是2哈.打印结果是2个对象 打了2次aardvark;  
      

  5.   

    String对象比较特殊,不管是哪个对象,只要他所指向的内容是一样的话,返回的哈希码是一样的,覆盖了Object类的hashCode()方法!另外String的equals方法也是覆盖Object中相应的方法。而HashSet判断两个对象是否相等,主要是通过这两个方法来的!
      

  6.   

    照你的说法是不是这样的? String s1 = new String("abc"); String s2 = new String("abc");
    2个abc字符串常量都在 内存常量池,所以它返回来的相对物理地址 一样....所以要自己去写hashCode 计算它的散列码值
    让它返回不一样的值...然后重写 hashCode 的时候又必然要去重写equals方法???effective java 这本书有点深哦 里面确实有讲到为什么有时候要重写equals方法...但是小弟确实难以理解那本书...
    看来这个问题要先放一下了 
      

  7.   

    Object的equals方法直接使用“==”去比较,比较的是两个引用变量所指的地址值,new了两个String对象的话,内存地址是不一样的,显然,这里不满足需求,这里要比较的是这两个字符串的内容是否是一样的。
      

  8.   

    只提示一句,Set 操作要求hashCode和equals方法
    tree 需要 compreTo 或者实现 Compareable 接口
      

  9.   

    晕,你要记住,JAVA比较两个对象是否一样是比较他们的内存地址是否一样。你是在内存中创建了两个string对象,它们的内存地址不一样,SET,肯定把他们当作不同的元素不加过滤。
      

  10.   


    boolean add(E o)
    如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。更正式地说,如果此 set 没有包含满足下列条件的元素 e,则向 set 中添加指定的元素 o:(o==null ? e==null :o.equals(e))。如果此 set 已经包含指定的元素,则该调用不改变此 set 并返回 false。结合构造方法上的限制,这就可以确保 set 永远不包含重复的元素。
    set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素
      

  11.   

     hs.add(new WrappedString("aardvark")); 
      hs.add(new WrappedString("aardvark")); 
    此处问题
    你ADD的是两个对象,虽然他们内部的值是相同的,但是对于HASHSET而言是不同的OBJECT,所以都被添加了.
    NEW 永远会产生新的对象,而不会去查找原来栈中是否已经有该对象
      

  12.   

    问题不在HashSet,在你的new String("aardvark"),这是两个不同的对象.你用hs.add("aardvark")就没有问题了.你的new String("aardvark"),在创建时首先丰字符池中寻找"aardvark",然后在堆栈中创建字符串对象"aardvark".但我用你的代码是1次.
      

  13.   


    package test;
    import java.util.*; public class HashSetTest {  public static void main(String[] args) { 
      HashSet hs = new HashSet();   hs.add(new String("aardvark")); 
      hs.add(new String("aardvark"));   //System.out.println(hs.size());    for (Iterator it = hs.iterator(); it.hasNext();) { 
       System.out.println(it.next()); 
      } 
     } 
    这样也不是只打针出一个吗,不知道你为什么要转来转去的,目标是什么不是很清楚
      

  14.   

    你用我代码打印出来一次是因为我重写了 equals和hashCode 的.如果我不覆盖那2个方法就是2次.