Person 类代码:
package test;public class Person {
  private String name;
  private int age;
  
  public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}@Override
public boolean equals(Object o) {
if(o==null) return false;
if(o==this) return true;

if(o instanceof Person ){
Person p=(Person)o;
if(p.name.equals(this.name)&&p.age==this.age){
return true;
}else{
return false;
}

}else{

return false;
}

}
@Override
public int hashCode() {
return this.name.hashCode()+age;
}
}这是测试代码:
package test;import java.util.HashSet;
import java.util.Set;public class TestHashSet {

public static void main(String[] args) {

Person p=new Person("llw",23);
Set<Person> persons=new HashSet<Person>();
persons.add(p);

System.out.println("persons.contains(p)--> "+persons.contains(p));
System.out.println("p.hashCode()--> "+p.hashCode());

Person getPerson=null;
Person check=null;

for(Person person:persons){

getPerson=person;
System.out.println("getPerson--> "+getPerson);
check=person;
}
getPerson.setAge(22);
System.out.println("getPerson--> "+getPerson);
System.out.println("after setAge()--> "+getPerson.hashCode());
System.out.println("after setAge() contain --> "+persons.contains(getPerson));
System.out.println("check.hashCode()--> "+check.hashCode());
System.out.println("is check in persons --> "+persons.contains(check));
}
运行结果:persons.contains(p)--> true
p.hashCode()--> 107278
getPerson--> test.Person@1a30e
getPerson--> test.Person@1a30d
after setAge()--> 107277
after setAge() contain --> false
check.hashCode()--> 107277
is check in persons --> false
本人在一个项目里遇到如下问题,就是输出结果里显示的
为什么从Set取出了元素并对其进行了修改后对象的地址会发生变化,也就是产生了新对象 
如果不重写hashCode()和equals() 结果就是正确的
这是为什么呢,哪们朋友帮忙回答一下啊?? 

解决方案 »

  1.   

    对象取地址就是用的hashcode 啊
    getClass().getName() + '@' + Integer.toHexString(hashCode())
    地址肯定有变化
      

  2.   

    那为什么执行了setAge()后
    persons.contains(getPerson);
    成了false呢??
    check.hasCode()和getPerson.hasCode()可是一样的啊
      

  3.   

    hashCode 的变化会引起对象地址的变化
      

  4.   

    那为什么执行了setAge()后 
    persons.contains(getPerson); 
    成了false呢?? 
    check.hasCode()和getPerson.hasCode()可是一样的啊
    这是关键。
      

  5.   

    LZ,你同一个类的实例由于某个数据的修改产生了两个截然不同的hasCode这肯定是不对的。Set集合是按照你hasCode的值进行散列的,你同一个对象前后的散列码不一样肯定返回false。
      

  6.   

        public int hashCode() {
            return this.name.hashCode();
        }hashCode方法你这样改肯定就对了。当然前提是你不修改name的数据。
      

  7.   

    check.hasCode()和getPerson.hasCode()可是一样的啊 
      

  8.   

    你Set里按照107278去散列的,然后你修改了数据hashCode变成了107277,你用107277去Set里找东西当然没结果了。你把哈希算法搞明白了,你就明白你的问题出在什么地方了。
      

  9.   

    NO ,在修改了getPerson之后,set 里面的元素的hasCode()和getPerson的hasCode()是一样的...
      

  10.   

    去google上查哈希算法,把哈希算法搞明白再来提问,别再说什么hashCode是一样的。
      

  11.   

    你最初把Person放入HashSet的时候,Set维护的散列映射是
    107278---p
    你修改了数据以后hashCode变成了107277,然后你问HashSet里有没有这个键映射的数据,要是有那就见鬼了。
      

  12.   

    首先,你修改对象并没有修改对象的地址或生成新对象。
    println()方法调用对象的toString()进行输出。
    在Object中toString()定义。public   String   toString()   {   
                  return   getClass().getName()   +   "@"   +                             Integer.toHexString         hashCode());   
            }   
    默认的hashCode()返回对象的内存地址,但hashCode已经被你重写了,就不会返回内存地址。
    2. HashSet 得contains方法是根据对象的hashCode和equals方法去判定的。
       先用hashCode,只有hashCode相同才去用equals方法。
      

  13.   

    请问 Alex_20同志,你运行了吗?
    你只是在那里说空话今天就让你见见鬼 
    你把我的运行一下,在最后的时候你再把set遍历一下看看,
    里面元素的hashCode的修改后的是相同的!!!
      

  14.   

    alex20说的是对的,可能你理解有问题
    Person放入HashSet,则hashSet的hash桶里会建立一个映射关系
    107278---p 
    你把person修改以后,hashcode变成了107277,HashSet.contain(person)是怎么来比较的呢?他不是遍历set来比较person和每个元素的hashcode是否相等。那样就不叫hashSet了!!!
    具体是这样的,它先获取待比较的元素person的hashcode,现在已经是107277,1在到hash桶里去取107277对应的元素
    2然后判断这2个元素的hashcode是否相等并且是否equal.
    由于之前的107278---p 对于修改都的元素来说是一个错误的映射,所以在hash桶里根本没有找到存放的这个元素,第2步都没有进行就直接返回false了当equals和hashCode依赖于会变化的状态时,那么就会给用户带来问题。如果这样的对象被放入到集合中,用户必须小心,不要修改这些这些对象所依赖的状态。如果你需要根据对象当前的状态进行比较的话,你应该不要再重定义equals,应该起其他的方法名字而不是equals
      

  15.   

    好现在把getPerson改了之后,它的hashCode()是107277
    你在改之后再去遍历set它的hashCode() 也是107277
    请调试 !!
      

  16.   

    没有人说遍历set它的hashCode()不是107277 !
    这又怎么样呢?上面已经说了,contain方法又不是遍历去比较的,问题的关键是他无法根据107277在hash桶里找到这个元素
      

  17.   

    你修改了数据后hashCode变化了,你通知了HashSet当前对象的hashCode发生变化要更新映射了吗?你不告诉HashSet,HashSet当然是按照最初的映射去查找,那能找到吗?居然还问我这程序运行了没有,我2001年就注册的帐号,大哥,不是新来的。
      

  18.   

    对不起了 ,Alex 同志,这是我项目里的一个问题,半天没有调出程序来,
    心里比较窝火,都怪自己基本功不扎实....
    希望你能理解..
    再次向你道歉了....
      

  19.   

    没关系,LZ,做开发最忌讳的就是心浮气躁,遇到问题别着急,静下心来多想,多尝试。
    其实往往最基础的东西才是最复杂的。
    多线程简单吧?在jdk1.4的时候一个synchronized关键字就解决同步的问题,可是真正能写出漂亮的多线程程序的程序员有多少?
    把功夫用在基础上绝对没错。