Object

作者: 寂静的春天1988 | 来源:发表于2020-05-10 20:26 被阅读0次

    原文链接: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();
        }
    }
    

    相关文章

      网友评论

          本文标题:Object

          本文链接:https://www.haomeiwen.com/subject/mtcsnhtx.html