Object

2020-05-10  本文已影响0人  寂静的春天1988

原文链接:https://www.cnblogs.com/dolphin0520/p/3681042.html

上面详细讲了equals和hashCode,以下是我的总结。

1、equals方法

    public boolean equals(Object obj) {
        return (this == obj);
    }

上面是object类的equals方法,可以看到object中是直接比较的地址值

某些情况下我们可能并不想比较地址值,而是比较两个对象的属性值是否相等,如果属性值都相等那么就认为是同一个对象!(额,并不会有这种情况!反正我是没遇到过。)

大家都知道我们只需要重写equals方法就可以了。

class People{
    private String name;
    private int age;
    public People(String name,int age) {
        this.name = name;
        this.age = age;
    }  
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        return this.name.equals(((People)obj).name) && this.age== ((People)obj).age;
    }
}
public class Main {
 
    public static void main(String[] args) {
         
        People p1 = new People("Jack", 12);
        System.out.println(p1.hashCode());
             
        HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
        hashMap.put(p1, 1);
         
        System.out.println(hashMap.get(new People("Jack", 12)));//null
    }
}

上面的代码重写了People类的equals方法,然后创建了一个name是Jack年龄是12的对象当做key,存储进了map中,但是get方法重新new了一个name是Jack年龄是12的对象,取值是却没有拿到1。

这段代码本来的意愿是想这段代码输出结果为“1”,但是事实上它输出的是“null”。为什么呢?原因就在于重写equals方法的同时忘记重写hashCode方法。

虽然通过重写equals方法使得逻辑上姓名和年龄相同的两个对象被判定为相等的对象(跟String类类似),但是要知道默认情况下,hashCode方法是将对象的存储地址进行映射。那么上述代码的输出结果为“null”就不足为奇了。原因就在于重写equals方法的同时忘记重写hashCode方法。

System.out.println(hashMap.get(new People("Jack", 12)));这句中的new People("Jack", 12)生成的是两个对象,它们的存储地址肯定不同。
map中get方法比较key是否相同时,首先比较hashcode是否相等,如果hashcode相等,那么再去调用equals方法是否相等,由于没有重写hashCode方法,默认hashCode方法与内存地址相关,hash算法根据内存地址获得一个hashCode,这里new的是两个people对象,那么当然hashcode码不一样,key不一样那么自然拿不到对应的value值!
 因此如果想上述代码输出结果为“1”,很简单,只需要重写hashCode方法,让equals方法和hashCode方法始终在逻辑上保持一致性。(这也就是为什么大家都说重写equals方法那么一定要重写hashCode方法,因为java中判断一个对象是否相等是根据hashcode和equals方法一起判断的,这两个方法的逻辑上一定要保持一致。)

下面这段话摘自Effective Java一书:

在程序执行期间,只要equals方法的比较操作用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法必须始终如一地返回同一个整数。
如果两个对象根据equals方法比较是相等的,那么调用两个对象的hashCode方法必须返回相同的整数结果。
如果两个对象根据equals方法比较是不等的,则hashCode方法不一定得返回不同的整数。

其实上面的代码不重写hashCode方法也有可能是能取到值的,因为java中不同的内存地址,根据hash算法也有可能算出来是相同的code码,但是可能性比较小。

最终总结:
因此有人会说,可以直接根据hashcode值判断两个对象是否相等吗?肯定是不可以的,因为不同的对象可能会生成相同的hashcode值。虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等,如果两个对象的hashcode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过equals方法。

也就是说对于两个对象,如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;(equals为true,那么地址值相同,内存地址值相同,那么hash算法算出的hashcode也一定相同。)

如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;(不同的内存地址值,hash算法也有较小可能得出相同的hashcode)

如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;(由第一条可以得出这条结论)

如果两个对象的hashcode值相等,则equals方法得到的结果未知。

3、clone
1、对象浅拷贝

public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        TestA ta=new TestA();
        TestA ta1=(TestA) ta.clone();
        System.out.println(ta1);
    }
}
class TestA implements Cloneable{
    public String name = "father";
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "TestA [name=" + name + "]";
    }
}

实现Cloneable接口,并且重写object类中的clone方法,即可。

浅拷贝:只将基本类型和String类型进行了拷贝。而所有的引用对象仍然指向原来的对象。换言之,浅拷贝不复制引用对象。

2、深拷贝

public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        TestA ta=new TestA();
        ta.name="aaa";
        ta.testB=new TestB(10);
        TestA ta1=(TestA) ta.clone();
        ta1.name="b";
        ta1.testB.age=20;
        System.out.println(ta1);
        System.out.println(ta);
    }
}

class TestA implements Cloneable{
    public String name;
    public TestB  testB;
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        TestA o = (TestA) super.clone();
        o.testB = (TestB) o.testB.clone();
        return o;
    }
    @Override
    public String toString() {
        return "TestA [name=" + name + ", testB=" + testB + "]";
    }
}

class TestB implements Cloneable{
    public int age;
    public TestB(int age) {
        this.age=age;
    }
    @Override
    public String toString() {
        return "TestB [age=" + age + "]";
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
上一篇 下一篇

猜你喜欢

热点阅读