天天看点

hashcode、equals和==

参考:http://blog.csdn.net/hzw19920329/article/details/51944114

1、equals和==

equals的作用是用来判断两个对象是否相等,Java中所有的类都实现了equals方法。在equals没有被重写的情况下equals等价于==

==比较(这里指对象比较)的是两个对象是否是同一个对象

public class User {
    private String username;
    private String pass;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    public User(String username, String pass) {
        super();
        this.username = username;
        this.pass = pass;
    }   
}   
           

用==测试

public static void main(String[] args) {
        User u1=new User("vivien","1234");
        User u2=new User("vivien","1234");
        System.out.println(u1==u2);
        System.out.println(u1.equals(u2));
        }
           

输出

false

false

尽管变量都一样,但是这两个毕竟不是同一个对象,所以执行==时显示false,而在没有重写equals的时候equals等价于==(String默认是重写了equals的,所以执行equals的时候new两个一样的String用equals比较是true)

重写equals:

public class User {
    private String username;
    private String pass;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    public User(String username, String pass) {
        super();
        this.username = username;
        this.pass = pass;
    }   
        @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if(obj==null)
            return false;
        if(obj==this)
            return true;
        if(obj instanceof User)
        {
            User o=(User)obj;
            if(o.getUsername()==this.username && o.getPass()==this.pass)
                return true;
            else return false;  
        }
        else
        {
            return false;
        }
    }
}
           

重新测试显示:

false

true

可以发现重写了equals之后输出true

注意equals原则:

1. 对称性:如果x.equals(y)返回是”true”,那么y.equals(x)也应该返回是”true”。

2. 反射性:x.equals(x)必须返回是”true”。

3. 类推性:如果x.equals(y)返回是”true”,而且y.equals(z)返回是”true”,那么z.equals(x)也应该返回是”true”。

4. 一致性:如果x.equals(y)返回是”true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是”true”。

5. 非空性,x.equals(null),永远返回是”false”;x.equals(和x不同类型的对象)永远返回是”false”。

2、equals和hashCode()

hashCode()的作用是获取哈希码,也称为散列码,返回的是一个int整数。

这两个如果不是在散列表中比较完全没有意思。因为如果这个类不是放在散列表中,equals和hashCode()没有半毛钱关系。

这里我以hashMap来说两者关系吧

HashMap解决冲突的方法时拉链法(把所有hashCode相同的键值对用单链表连接起来),这也导致了HahMap的结构–数组+链表:

hashcode、equals和==

每个键值对在hashMap中是以Entry的形式存在

HashMap的put原理:

首先用hashCode()方法计算当前key的hash值,接着找到计算出来的hash值在数组中的下标位置,查看该下标位置处对应的链表是否为null,为null的话直接将当前键值对插入到该链表首位。如果下标位置处对应的链表不为null的话,会使用for循环,每次循环通过key的equals()方法查看这个链表中有没有与当前键值对相等的Entry存在,有的话会用当前值替换原先这个键值对的value值,遍历结束如果不存在的话,会将当前键值对插入到链表头部。

HashMap的get原理

get操作过程思想可以借助于put过程,首先会计算出当前key值的hash值,接着找到此hash值在数组中的位置,找到这个位置对应的链表,接着通过for循环遍历这个链表,遍历过程中调用equals方法查看有没有等于当前key的键值对存在,有的话直接返回这个键值对对应的value值即可

所以HashMap 如果想要实现让对象做key,并且相同变量的对象视为相同的key的话,一定要重写equals()方法和hashCode()方法。什么意思呢,直接看例子:

上面的User类如果我没有重写equals()方法和hashCode()方法,把User类作为key,存到HashMap中时:

public static void main(String[] args) {
        Map<User,String> m=new HashMap<User,String>();
        User u1=new User("vivien","1234");
        User u2=new User("vivien","1234");
        m.put(u1, "这是u1");
        m.put(u2, "这是u2");
        System.out.println("u1 hashCode():"+u1.hashCode());
        System.out.println("u2 hashCode():"+u2.hashCode());
        System.out.println("u1.equals(u2)?"+u1.equals(u2));
        Set<Map.Entry<User, String>> entries=m.entrySet();
        Iterator it=entries.iterator();
        while(it.hasNext())
            System.out.println(it.next());
    }
           

输出(为了输出直观,为在User中重写了toString()方法):

u1 hashCode():1704856573

u2 hashCode():705927765

u1.equals(u2)?false

User [username=vivien, pass=1234]=这是u1

User [username=vivien, pass=1234]=这是u2

很显然,u1和u2hashCode不一样,并且也不equals,HashMap把u1和u2当做两个key来对待

现在重写equals和hashCode()方法:

public class User {
    private String username;
    private String pass;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }

    @Override
    public String toString() {
        return "User [username=" + username + ", pass=" + pass
                + "]";
    }
    public User(String username, String pass) {
        super();
        this.username = username;
        this.pass = pass;
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if(obj==null)
            return false;
        if(obj==this)
            return true;
        if(obj instanceof User)
        {
            User o=(User)obj;
            if(o.getUsername()==this.username && o.getPass()==this.pass)
                return true;
            else return false;  
        }
        else
        {
            return false;
        }
    }
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return (this.username+this.pass).hashCode();
    }
}   
           

重新运行上面的test:

u1 hashCode():-1331478383

u2 hashCode():-1331478383

u1.equals(u2)?true

User [username=vivien, pass=1234]=这是u2

这时可以看到,在插入u2时,HashMap首先计算u2 hashCode,找到了与u1相同hashCode的链,在这个链中,通过for循环发现u1的key equals u2的key,所以把u2对应的value覆盖u1对应的value。所以最后遍历Map发现只有一个键值对