聊聊hashcode和equals

基本概念

hashcode:
有人说hashcode就是对象的内存地址,这种说法其实过于绝对,应该是根据不同的jvm实现决定的。 我理解hashcode的作用是返回哈希码,确定对象在hash表中的位置,所以仅仅当使用散列表的类【hashset, hashmap, hashtable】的时候才有重写的意义。如果是非散标的集合(比如list),就只需要重写equals了。如果不重写则返回Object中的默认实现。

equals:

说到equals,必须说下”==”,前者是比较对象的内容,后者是比较对象的地址。默认是采用Object中的equals方法,用“==“比较,即比较对象的地址。

举例说明:

后面就通过四个实例来验证以上的结论。
假设我们有一个Person类,如果名字相同我们就确认他们是同一个类。

  • 1.不重写 hashcode和equals方法:
public class Person {

    private String name;
    private Integer age;
    private String desc;

    public Person(){

    }
    public Person(String name,Integer age){
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}



public class TestHashCode {
    public static void main(String[] args) {
        Person p = new Person("张三", 12);
        Person p2 = new Person("张三", 12);
        System.err.println("==:"+(p == p2));
        System.err.println("equals:"+(p.equals(p2)));
        HashSet<Person> pSet = new HashSet<Person>();
        pSet.add(p);
        pSet.add(p2);
        System.err.println("pSet: "+pSet.size());       

        List<Person> plist=new ArrayList<Person>();
        plist.add(p);
        plist.add(p2);
        System.err.println("plist: "+plist.size());
    }
}

执行结果:
==:false
equals:false
pSet: 2
plist: 2
  • 2.重写equals方法:
public class Person {

    private String name;
    private Integer age;
    private String desc;

    public Person(){

    }
    public Person(String name,Integer age){
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

public class TestHashCode {
    public static void main(String[] args) {
        Person p = new Person("张三", 12);
        Person p2 = new Person("张三", 12);
        System.err.println("==:"+(p == p2));
        System.err.println("equals:"+(p.equals(p2)));
        HashSet<Person> pSet = new HashSet<Person>();
        pSet.add(p);
        pSet.add(p2);
        System.err.println("pSet: "+pSet.size());       

        List<Person> plist=new ArrayList<Person>();
        plist.add(p);
        plist.add(p2);
        System.err.println("plist: "+plist.size());
    }
}

执行结果:
==:false
equals:true
pSet: 2
plist: 2
  • 3.重写hashcode方法:
public class Person {

    private String name;
    private Integer age;
    private String desc;

    public Person(){

    }
    public Person(String name,Integer age){
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

        @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
}



public class TestHashCode {
    public static void main(String[] args) {
        Person p = new Person("张三", 12);
        Person p2 = new Person("张三", 12);
        System.err.println("==:"+(p == p2));
        System.err.println("equals:"+(p.equals(p2)));
        HashSet<Person> pSet = new HashSet<Person>();
        pSet.add(p);
        pSet.add(p2);
        System.err.println("pSet: "+pSet.size());       

        List<Person> plist=new ArrayList<Person>();
        plist.add(p);
        plist.add(p2);
        System.err.println("plist: "+plist.size());
    }
}

执行结果:
==:false
equals:false
pSet: 2
plist: 2
  • 4.重写equals和hashcode方法:
public class Person {

    private String name;
    private Integer age;
    private String desc;

    public Person(){

    }
    public Person(String name,Integer age){
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

        @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
}



public class TestHashCode {
    public static void main(String[] args) {
        Person p = new Person("张三", 12);
        Person p2 = new Person("张三", 12);
        System.err.println("==:"+(p == p2));
        System.err.println("equals:"+(p.equals(p2)));
        HashSet<Person> pSet = new HashSet<Person>();
        pSet.add(p);
        pSet.add(p2);
        System.err.println("pSet: "+pSet.size());       

        List<Person> plist=new ArrayList<Person>();
        plist.add(p);
        plist.add(p2);
        System.err.println("plist: "+plist.size());
    }
}

执行结果:
==:false
equals:true
pSet: 1
plist: 2

- 结果分析:
我们可以看到,以上四种实验,验证了几下几个结论。
1.“==“”比较是内存地址; 未重写的对象equals也是比较的内存地址(Object类中的equals方法)
2.hashcode只是针对使用散列表的对象才有意义,例子中的list就没有什么意义,只需要重写equals就足够了。
3.对于需要用到散列表结构【比如示例中的hashSet】的对象,必须把hashcode以及equals一起重写,否则就会有潜藏的bug,见第二种情况,只是重写了equals,但是没有达到我们的目标。 因为对于hashset来说,首先判断对象的hashcode,如果hashcode不相等,则直接认为两对象不相等;如果hashcode相等,则再去判断equals。

猜你喜欢

转载自blog.csdn.net/xuxian6823091/article/details/81071078