精华内容
下载资源
问答
  • equals方法

    万次阅读 2018-06-28 19:50:31
    因为Java中所有类都继承自Object类,所以Java中的所有对象都有equals方法。 /** * Object类默认的equals()方法 */ public boolean equals(Object obj) { return (this == obj); } 重写equals方法 Object的...

    因为Java中所有类都继承自Object类,所以Java中的所有对象都有equals方法。

    /**
     * Object类默认的equals()方法
     */
    public boolean equals(Object obj) {
            return (this == obj);
        }

    重写equals方法

    Object的equals方法默认比较的是引用(对象地址),有些时候不能满足我们的需求,比如我们定义一个不允许有重复值的对象数组,规定两个对象内成员变量的值相同,这两个对象就重复,当我们向对象内插入对象时,必然要先判断插入的对象是否在数组中存在,如果存在就替换,不存在就插入,但是用equals方法显然判断不出,因为new出来的对象的内存地址肯定不同,所以数组中的值难免会重复,这时候就要重写对象类的equals方法,在其中加入我们自己的逻辑。

    未重写equals方法

    public class EqualsTest {
        public static void main(String[] args) {
            // 定义students列表,不允许学生重名。
            List<Student> students = new ArrayList<>();
            Student student;
            // 重复插入10次小明
            for (int i = 0; i < 10; i++) {
                student = new Student("小明");
                if (!students.contains(student)) {
                    students.add(student);
                }
            }
            System.out.println(students.size());
        }
    }
    
    class Student {
        private String name;
    
        public Student(String name) {
            this.name = name;
        }
    }

    运行结果:
    这里写图片描述
    我们期望的输出结果是1,这里运行结果输出为10,插入了10个重名的同学,很明显不符合我们的需求

    重写equals方法

    public class EqualsTest {
        public static void main(String[] args) {
            // 定义students列表,不允许学生重名。
            List<Student> students = new ArrayList<>();
            Student student;
            // 重复插入10次小明
            for (int i = 0; i < 10; i++) {
                student = new Student("小明");
                if (!students.contains(student)) {
                    students.add(student);
                }
            }
            System.out.println(students.size());
        }
    }
    
    class Student {
        private String name;
    
        public Student(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        /**
         * 重写equals方法
         *
         * @param obj
         * @return
         */
        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (obj instanceof Student) {
                Student student = (Student) obj;
                if (student.getName().equals(this.name)) {
                    return true;
                }
            }
            return false;
        }
    }

    运行结果:
    这里写图片描述
    重写equals方法后运行结果符合期望

    重写hashCode方法

    hashcode的作用

    利用HashSet/HashMap/Hashtable类来存储数据时,为了提高程序的效率,先进行hashcode的比较,如果不同,那没就不必在进行equals的比较了,这样大大减少了equals比较的次数,从而大幅度提高了效率。

    JDK的API建议:equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。常规协定如下
    (1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true
    (2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false

    上面的例子中,我们重写了equals方法,并规定只要对象的name属性值相同,两个对象就相等,很显然我们的目的可以轻松达到。但是我们没有重写hashCode方法。hashCode方法仍然返回的对象的内存地址,所以两个对象的hashCode值还是不相等,这就违反了hashCode 方法的常规协定。后果是,在某些利用对象hashCode值做索引的情况下,这样会造成混乱,相当于没有重写equals方法。

        /**
         * 重写Student类的hashCode方法
         *
         * @return
         */
        @Override
        public int hashCode() {
            return this.name.hashCode();
        }

    equals的其他规定

    自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
    对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
    传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
    一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
    对于任何非空引用值 x,x.equals(null) 都应返回 false。

    展开全文
  • 重写hashcode和equals方法

    万次阅读 多人点赞 2019-05-07 21:55:43
    一。前言 我们都知道,要比较两个对象是否相等时需要调用对象的equals()方法,即判断对象引用所指向的对象地址是否相等,对象地址相等...对象在不重写的情况下使用的是Object的equals方法和hashcode方法,从Object...


     

    一。前言

    我们都知道,要比较两个对象是否相等时需要调用对象的equals()方法,即判断对象引用所指向的对象地址是否相等,对象地址相等时,那么与对象相关的对象句柄、对象头、对象实例数据、对象类型数据等也是完全一致的,所以我们可以通过比较对象的地址来判断是否相等。

    二。Object源码理解

    对象在不重写的情况下使用的是Object的equals方法和hashcode方法,从Object类的源码我们知道,默认的equals 判断的是两个对象的引用指向的是不是同一个对象;而hashcode也是根据对象地址生成一个整数数值;

    另外我们可以看到Object的hashcode()方法的修饰符为native,表明该方法是否操作系统实现,java调用操作系统底层代码获取哈希值。

     

    public class Object {
    
    public native int hashCode();
    
        /**
         * Indicates whether some other object is "equal to" this one.
         * <p>
         * The {@code equals} method implements an equivalence relation
         * on non-null object references:
         * <ul>
         * <li>It is <i>reflexive</i>: for any non-null reference value
         *     {@code x}, {@code x.equals(x)} should return
         *     {@code true}.
         * <li>It is <i>symmetric</i>: for any non-null reference values
         *     {@code x} and {@code y}, {@code x.equals(y)}
         *     should return {@code true} if and only if
         *     {@code y.equals(x)} returns {@code true}.
         * <li>It is <i>transitive</i>: for any non-null reference values
         *     {@code x}, {@code y}, and {@code z}, if
         *     {@code x.equals(y)} returns {@code true} and
         *     {@code y.equals(z)} returns {@code true}, then
         *     {@code x.equals(z)} should return {@code true}.
         * <li>It is <i>consistent</i>: for any non-null reference values
         *     {@code x} and {@code y}, multiple invocations of
         *     {@code x.equals(y)} consistently return {@code true}
         *     or consistently return {@code false}, provided no
         *     information used in {@code equals} comparisons on the
         *     objects is modified.
         * <li>For any non-null reference value {@code x},
         *     {@code x.equals(null)} should return {@code false}.
         * </ul>
         * <p>
         * The {@code equals} method for class {@code Object} implements
         * the most discriminating possible equivalence relation on objects;
         * that is, for any non-null reference values {@code x} and
         * {@code y}, this method returns {@code true} if and only
         * if {@code x} and {@code y} refer to the same object
         * ({@code x == y} has the value {@code true}).
         * <p>
         * Note that it is generally necessary to override the {@code hashCode}
         * method whenever this method is overridden, so as to maintain the
         * general contract for the {@code hashCode} method, which states
         * that equal objects must have equal hash codes.
         *
         * @param   obj   the reference object with which to compare.
         * @return  {@code true} if this object is the same as the obj
         *          argument; {@code false} otherwise.
         * @see     #hashCode()
         * @see     java.util.HashMap
         */
        public boolean equals(Object obj) {
            return (this == obj);
        }
    }

    三。需要重写equals()的场景

     

    假设现在有很多学生对象,默认情况下,要判断多个学生对象是否相等,需要根据地址判断,若对象地址相等,那么对象的实例数据一定是一样的,但现在我们规定:当学生的姓名、年龄、性别相等时,认为学生对象是相等的,不一定需要对象地址完全相同,例如学生A对象所在地址为100,学生A的个人信息为(姓名:A,性别:女,年龄:18,住址:北京软件路999号,体重:48),学生A对象所在地址为388,学生A的个人信息为(姓名:A,性别:女,年龄:18,住址:广州暴富路888号,体重:55),这时候如果不重写Object的equals方法,那么返回的一定是false不相等,这个时候就需要我们根据自己的需求重写equals()方法了。

    package jianlejun.study;
    
    public class Student {
    	private String name;// 姓名
    	private String sex;// 性别
    	private String age;// 年龄
    	private float weight;// 体重
    	private String addr;// 地址
    	
    	// 重写hashcode方法
    	@Override
    	public int hashCode() {
    		int result = name.hashCode();
    		result = 17 * result + sex.hashCode();
    		result = 17 * result + age.hashCode();
    		return result;
    	}
    
    	// 重写equals方法
    	@Override
    	public boolean equals(Object obj) {
    		if(!(obj instanceof Student)) {
           // instanceof 已经处理了obj = null的情况
    			return false;
    		}
    		Student stuObj = (Student) obj;
    		// 地址相等
    		if (this == stuObj) {
    			return true;
    		}
    		// 如果两个对象姓名、年龄、性别相等,我们认为两个对象相等
    		if (stuObj.name.equals(this.name) && stuObj.sex.equals(this.sex) && stuObj.age.equals(this.age)) {
    			return true;
    		} else {
    			return false;
    		}
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getSex() {
    		return sex;
    	}
    
    	public void setSex(String sex) {
    		this.sex = sex;
    	}
    
    	public String getAge() {
    		return age;
    	}
    
    	public void setAge(String age) {
    		this.age = age;
    	}
    
    	public float getWeight() {
    		return weight;
    	}
    
    	public void setWeight(float weight) {
    		this.weight = weight;
    	}
    
    	public String getAddr() {
    		return addr;
    	}
    
    	public void setAddr(String addr) {
    		this.addr = addr;
    	}
    
    }
    

    现在我们写个例子测试下结果:

    public static void main(String[] args) {
    	Student s1 =new Student();
    	s1.setAddr("1111");
    	s1.setAge("20");
    	s1.setName("allan");
    	s1.setSex("male");
    	s1.setWeight(60f);
    	Student s2 =new Student();
    	s2.setAddr("222");
    	s2.setAge("20");
    	s2.setName("allan");
    	s2.setSex("male");
    	s2.setWeight(70f);
    	if(s1.equals(s2)) {
    		System.out.println("s1==s2");
    	}else {
    		System.out.println("s1 != s2");
    	}
    }

    在重写了student的equals方法后,这里会输出s1 == s2,实现了我们的需求,如果没有重写equals方法,那么上段代码必定输出s1!=s2。

    通过上面的例子,你是不是会想,不是说要同时重写Object的equals方法和hashcode方法吗?那上面的例子怎么才只用到equals方法呢,hashcode方法没有体现出来,不要着急,我们往下看。

    四。需要重写hashcode()的场景

    以上面例子为基础,即student1和student2在重写equals方法后被认为是相等的。

    在两个对象equals的情况下进行把他们分别放入Map和Set中

    在上面的代码基础上追加如下代码:

    Set set = new HashSet();
    	set.add(s1);
    	set.add(s2);
    	System.out.println(set);

    如果没有重写Object的hashcode()方法(即去掉上面student类中hashcode方法块),这里会输出

    [jianlejun.study.Student@7852e922, jianlejun.study.Student@4e25154f]

    说明该Set容器类有2个元素。.........等等,为什么会有2个元素????刚才经过测试,s1不是已经等于s2了吗,那按照Set容器的特性会有一个去重操作,那为什么现在会有2个元素。这就涉及到Set的底层实现问题了,这里简单介绍下就是HashSet的底层是通过HashMap实现的,最终比较set容器内元素是否相等是通过比较对象的hashcode来判断的。现在你可以试试吧刚才注释掉的hashcode方法弄回去,然后重新运行,看是不是很神奇的就只输出一个元素了

    @Override
    	public int hashCode() {
    		int result = name.hashCode();
    		result = 17 * result + sex.hashCode();
    		result = 17 * result + age.hashCode();
    		return result;
    	}

     或许你会有一个疑问?hashcode里的代码该怎么理解?该如何写?其实有个相对固定的写法,先整理出你判断对象相等的属性,然后取一个尽可能小的正整数(尽可能小时怕最终得到的结果超出了整型int的取数范围),这里我取了17,(好像在JDK源码中哪里看过用的是17),然后计算17*属性的hashcode+其他属性的hashcode,重复步骤。

    重写hashcode方法后输出的结果为:

    [jianlejun.study.Student@43c2ce69]

     

    同理,可以测试下放入HashMap中,key为<s1,s1>,<s2,s2>,Map也把两个同样的对象当成了不同的Key(Map的Key是不允许重复的,相同Key会覆盖)那么没有重写的情况下map中也会有2个元素,重写的情况会最后put进的元素会覆盖前面的value

    Map m = new HashMap();
    	m.put(s1, s1);
    	m.put(s2, s2);
    	System.out.println(m);
    	System.out.println(((Student)m.get(s1)).getAddr());
    
    输出结果:
    {jianlejun.study.Student@43c2ce69=jianlejun.study.Student@43c2ce69}
    222

     可以看到最终输出的地址信息为222,222是s2成员变量addr的值,很明天,s2已经替换了map中key为s1的value值,最终的结果是map<s1,s2>。即key为s1value为s2.

     五。原理分析

    因为我们没有重写父类(Object)的hashcode方法,Object的hashcode方法会根据两个对象的地址生成对相应的hashcode;

    s1和s2是分别new出来的,那么他们的地址肯定是不一样的,自然hashcode值也会不一样。

    Set区别对象是不是唯一的标准是,两个对象hashcode是不是一样,再判定两个对象是否equals;

    Map 是先根据Key值的hashcode分配和获取对象保存数组下标的,然后再根据equals区分唯一值(详见下面的map分析)

     

    六。补充HashMap知识

    hashMap组成结构:hashMap是由数组和链表组成;

    hashMap的存储:一个对象存储到hashMap中的位置是由其key 的hashcode值决定的;查hashMap查找key: 找key的时候hashMap会先根据key值的hashcode经过取余算法定位其所在数组的位置,再根据key的equals方法匹配相同key值获取对应相应的对象;

    案例:

    (1)hashmap存储

    存值规则:把Key的hashCode 与HashMap的容量 取余得出该Key存储在数组所在位置的下标(源码定位Key存储在数组的哪个位置是以hashCode & (HashMap容量-1)算法得出)这里为方便理解使用此方式;

    //为了演示方便定义一个容量大小为3的hashMap(其默认为16)

    HashMap map=newHashMap(3);

    map.put("a",1); 得到key 为“a” 的hashcode 值为97然后根据 该值和hashMap 容量取余97%3得到存储位到数组下标为1;

    map.put("b",2); 得到key 为“b” 的hashcode 值为98,98%3到存储位到数组下标为2;

    map.put("c",3); 得到key 为“c” 的hashcode 值为99,99%3到存储位到数组下标为0;

    map.put("d",4); 得到key 为“d” 的hashcode 值为100,100%3到存储位到数组下标为1;

    map.put("e",5); 得到key 为“e” 的hashcode 值为101,101%3到存储位到数组下标为2;

    map.put("f",6); 得到key 为“f” 的hashcode 值为102,102%3到存储位到数组下标为0;

     

     

     

     

     

     

    (2)hashmap的查找key

    得到key在数组中的位置:根据上图,当我们获取key 为“a”的对象时,那么我们首先获得 key的hashcode97%3得到存储位到数组下标为1;

    匹配得到对应key值对象:得到数组下表为1的数据“a”和“c”对象, 然后再根据 key.equals()来匹配获取对应key的数据对象;

    hashcode 对于HashMapde:如果没有hashcode 就意味着HashMap存储的时候是没有规律可寻的,那么每当我们map.get()方法的时候,就要把map里面的对象一一拿出来进行equals匹配,这样效率是不是会超级慢;

     

    5、hashcode方法文档说明

    在equals方法没被修改的前提下,多次调用同一对象的hashcode方法返回的值必须是相同的整数;

    如果两个对象互相equals,那么这两个对象的hashcode值必须相等;

    为不同对象生成不同的hashcode可以提升哈希表的性能;

    展开全文
  • 重写equals方法

    2019-12-02 17:23:40
    重写equals方法 相信在每个人都有过重写过java的equals的方法的经历。这篇博文就从以下几个方面说明重写equals方法的原由,与君共进步。 一 为什么要重写equals方法 首先我们了解equals方法的作用是什么? java的...

    重写equals方法

    相信在每个人都有过重写过java的equals的方法的经历。这篇博文就从以下几个方面说明重写equals方法的原由,与君共进步。

    在这里插入图片描述

    一 为什么要重写equals方法

    首先我们了解equals方法的作用是什么?

    java的官方解释:

    Indicates whether some other object is “equal to” this one.

    The equals method implements an equivalence relation on non-null object references:

    指示某个其他对象是否“等于”这个对象。
    equals方法实现了非空对象引用的等价关系.

    也就是说比较两个对象是否相等,在Object类中,这个方法是用来判断两个对象是否具有相同的引用。如果两个对象具有相同的引用,那么他们一定是相等的,看看下面这段代码的运行:

        public static void main(String[] args) {
        Object o1 = new Object();   
        Object o2 =o1;
        Object o3 = o1;
        System.out.println(o3.equals(o2));
    }
    

    结果是

    输出是:  true  
    

    这是因为o2和o3来两个对象都指向了相同的引用o1,所以是true。 但是很多时侯我们可能会有这样的需求。比较两个对象的状态(内容)是否相同。看看下面着段代码:

    public class Student {
    
    private String name;
    
    public Student() {
    }
    
    public Student(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    public static void main(String[] args) {
         Student stu1 = new Student("张三");
         Student stu2 = new Student("张三");
         System.out.println(stu1.equals(stu2));
         System.out.println(stu1==stu2);
    }
    

    }

    结果是

    false
    false
    

    分析: 为什么使用equals方法返回的不是true,而是和==相同的结果false呢。这是因为Student这个类并没有重写equals方法,当调用equals方法时,实际上调用的是Object类中的equals方法。看看equals方法的源码:

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

    可以看到equals的底层代码使用 == 来实现的,也就是说在此时的equals方法也是利用 ==来比较的两个对象的内存地址是否相同。

    所以上面的代码运行结果都是false。
    所以要想实现两个对象的状态(内容)相同,就要重写equals方法

    重写student类中的equals方法:

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        Student student = (Student) o;
        return 
        Objects.equals(name, student.name);
    }
    

    再次运行:

     true
     false
    

    可以看到,重写了equals方法实现了两个对象的状态比较。使用equals返回的是true。

    重写eqauls方法能实现两个对象的状态(内容)比较。

    二 重写equals方法的原则是什么

    看官方文档给出的解释

    • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
    • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
    • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
    • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
    • For any non-null reference value x, x.equals(null) should return false.

    也就是,重写equals方法时,必须满足下面原则

    • 自反性:对于任何非空参考值x,x.equals(x)应该返回true。
    • 对称性:对于任何非空参考值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。
    • 传递性:对于x,y和z的任何非空引用值,如果x.equals(y)返回true,而y.equals(z)返回true,则x.equals(z)应该返回true。
    • 一致性:对于任何非空引用值x和y,只要未修改对象的equals比较中使用的信息,对x.equals(y)的多次调用将始终返回true或始终返回false。
    • 对于任何非null参考值x,x.equals(null)应该返回false。

    一般而言,对于一个类的两个对象,这五个原则都可以满足。看下面的代码:

         public static void main(String[] args) {
         Student stu = null;
         Student stu1 = new Student("张三");
         Student stu2 = new Student("张三");
         Student stu3 =  new Student("张三");
         System.out.println("自反性:"+stu1.equals(stu1));
         System.out.println("对称性");
         System.out.println(stu1.equals(stu2));
         System.out.println(stu2.equals(stu1));
         System.out.println("传递性");
         System.out.println(stu1.equals(stu2));
         System.out.println(stu2.equals(stu3));
         System.out.println(stu1.equals(stu3));
         System.out.println("一致性:");
        for(int i =0; i<5;i++){
            if(stu1.equals(stu2)!=stu1.equals(stu2)){
                System.out.println("没有遵守一致性");
                break;
            }
        }
        System.out.println("遵守了一致性");
        System.out.println("非空性");
        // 这里的stu对象为null,所以返回false
        System.out.println(stu1.equals(stu));
    }
    

    输出结果:

    自反性:true
    对称性
    true
    true
    传递性
    true
    true
    true
    一致性:
    遵守了一致性
    非空性
    false
    

    测试这几个原则都能满足

    如果一个类中含有继承关系,equals方法是否满足呢。我们让student类继承person类。看下面的代码

    public class Person {
    private int age;
    
    public Person(){}
    
    public Person(int age) {
        this.age = age;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    // 实现父类equals的方法比较。
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
        Person person = (Person) o;
        return age == person.age;
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(age);
    }
     }
    

    让student继承person,并且有自己的独有的属性name。

    public class Student extends Person {
    private String name;
    public Student() {
    }
    public Student(String name){
        this.name = name;
    }
    public Student(int batch,String name) {
        super(batch);
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        if (!super.equals(o)) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name);
    }
    

    测试:

      public static void main(String[] args) {
       Person per1 = new Person(12);
      Student stu2 = new Student(12,"张三");
       System.out.println(per1.equals(stu2));
       System.out.println(stu2.equals(per1));
    }
    

    运行结果:

    true 
    false 
    

    为什么出现了false呢,这是因为违背了对称性的原则了。分析一下也不难理解,因为student都是person,所以,per1.equals(stu2)是true,但是反过来就不成立,你不能说所有person都是student,所以stu2.equals(per1)是不成立的。这里也要明确一下父类和字类的equals方法的调用关系。在子类中定义equals方法时,首先调用父类的equals方法,如果检测失败,对象就不可能相等,如果超类中的域都相等,才需要比较子类的实例域。那么上述这个问题怎么解决呢,明白了equals方法的调用关系,那就只需在子类中的eqauls方法中添加一个判断。

     // 修改student类中的equals方法
    @Override
    public boolean equals(Object o) {
      if (this == o) return true;
      // 记得注释这里
      //if (!(o instanceof Student)) return false;
        if (!super.equals(o)) return false;
        if(o instanceof Student){
            Student student = (Student) o;
            return Objects.equals(name, student.name);
        }
        // 如果o不是student还需要再判断o 是不是person对象
        return super.equals(o);
    }
    

    再次运行上述代码:

    true 
    true 
    

    就符合对称性了。

    三 重写了equals方法为什么还要重写hashcode呢

    看看hashcode的定义:
    java官方档对hashcode()方法的解释:

    Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by HashMap.

    返回对象的哈希码值。支持此方法的好处是可以使用HashMap提供的散列表。

    官方文档明确的说明了此方法的好处是可以使用HashMap提供的散列表。这是因为Map接口的类会使用到键对象的哈希码,当我们调用put方法时,就是根据对象的哈希码来计算存储位置的,因此必须提供对哈希码正确的保证。在java中,可以使用hashCode()这个方法来获取对象的哈希值。

    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "world";
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
    }
    

    输出结果:

    99162322
    113318802
    

    可以看到不同的对象的hashcode值是不同的。

    看看javaAPI的对hashcode的几点说明:

    • 在Java应用程序的执行过程中,无论何时在同一个对象上多次调用它,hashCode方法都必须一致地返回相同的整数,前提是不对对象上的equals比较中使用的信息进行修改。此整数不需要在应用程序的一次执行与同一应用程序的另一次执行之间保持一致。

    • 如果根据equals(Object)方法,两个对象是相等的,那么在每个对象上调用hashCode方法必须产生相同的整数结果。

    • 如果两个对象根据equals(java.lang.Object)方法是不相等的,那么在每个对象上调用hashCode方法必须产生不同的整数结果,这是不需要的。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

      回到我们前面的问题,为什么重写equals方法,必须要重写hashcode方法。在Object类中,hashCode方法是通过Object对象的地址计算出来的,因为Object对象只与自身相等,所以同一个对象的地址总是相等的,计算取得的哈希码也必然相等。对于不同的对象,由于地址不同,所获取的哈希码自然也不会相等。所以如果一个类重写了equals方法,但没有重写hashCode方法,将会直接违法了第2条规定。还有一点就是重写hashcode()方法,可以方便用户将对象插入到散列表中。

    四 如何写好一个equals方法

    1. 显式参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量。
    2. 检测this与otherObject是否引用同一个对象:if(this=otherObject)returntrue;这条语句只是一个优化。实际上,这是一种经常采用的形式。因为计算这个等式要比一个一个地比较类中的域所付出的代价小得多。
    3. 检测otherObject是否为null,如果为null,返回false。这项检测是很必要的。if(otherObject=null)returnfalse;
    4. 比较this与otherObject是否属于同一个类。如果equals的语义在每个子类中有所改变,就使用getClass检测:if(getClass()!=otherObject.getCIassO)returnfalse;如果所有的子类都拥有统一的语义,就使用instanceof检测:if(!(otherObjectinstanceofClassName))returnfalse;
    5. 将otherObject转换为相应的类类型变量:ClassNameother=(ClassName)otherObject
    6. 现在开始对所有需要比较的域进行比较了。使用=比较基本类型域,使用equals比较对象域。如果所有的域都匹配,就返回true;否则返回false。returnfieldl==other.field&&Objects.equa1s(fie1d2,other.field2)
    7. 如果在子类中重新定义equals,就要在其中包含调用super.equals(other)。

    如果你用的是eclipse或者是idea集成环境的话,可以使用快捷键自动生成符合以上标准的equals()方法,但是有时候需要自定义,所以知道原理很重要。

    追本溯源,方能阔步前行

    参考书籍:

    1. Java核心技术 第一卷:基础知识

    2. java官方文档

    展开全文
  • equals方法和hashCode方法 创建User类,重写它的equals方法和hashCode方法。 public class User { private Integer userId; private String account; private String key; private Character sex; private ...

    equals方法和hashCode方法



    创建User类,重写它的equals方法和hashCode方法。

    public class User {
        private Integer userId;
        private String account;
        private String key;
        private Character sex;
        private Integer age;
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            User user = (User) o;
            return Objects.equals(userId, user.userId) &&
                    Objects.equals(account, user.account) &&
                    Objects.equals(key, user.key) &&
                    Objects.equals(sex, user.sex) &&
                    Objects.equals(age, user.age);
        }
        @Override
        public int hashCode() {
            return Objects.hash(userId, account, key, sex, age);
        }
    }
    

    equals 方法解析:

    if (this == o) return true; 当这个对象等于它自己的时候,返回true; 例如user.equals(user);

    if (o == null || getClass() != o.getClass()) return false; 判断传入对象是否为null或是否是别的类型,返回flase; 例如user.equals(null);

    User user = (User) o; 将传入对象转换为User对象。

    return 之后的返回值 为每个属性值的比较。

    当然在这里插入图片描述 是调用了Objects的equals方法,而调用什么方法,取决于什么参数,如果参数都是String类型,则会调用String类的equals方法,因为String是Object的子类。【即父类声明调用子类方法】

    那就看看Objects的equals方法怎么实现的
    点开equals的源码:
    在这里插入图片描述
    (a ==b)||(a != null && a.equals(b));

    先比较a与b的内容和内存地址是否一致,再比较 a的值是否为空与e.equals(b);
    点开e.equals(b)中的equals中的源码:
    在这里插入图片描述
    可以看出,这里是判断这两个值的内存地址是否相等。
    也就是说。如果是基本类型,则可以按照(a == b)的方式直接判断,如果是引用类型,则按照equals方法进行比较。


    hashCode 方法解析:

    在这里插入图片描述
    点看hash方法,查看源码:
    在这里插入图片描述
    这里调用了Arrays的hashCode方法,

    但是注意参数列表中存在在这里插入图片描述 (Object… valuse)
    其中 … 表示不确定参数个数,所有用了 … 来代替所传来的参数

    继续点看hashCode(values)的源码:
    在这里插入图片描述

    在这段的参数列表中也可以看出, 在调用Arrays.hashCode(valuse)方法时,传递的参数也是以数组的形式记录了。

    第一个if判断 : 当a[]为空时,则哈希码就是0;

    如果不为空,则执行下面的循环部分,
    在这里插入图片描述
    带参数解释下:
    假定这个对象为 User u = new User(“userId”,“account”,'key",“sex”,“age”);
    那么这个数组长度就是5,则会进行5次循环
    第一次循环:result = 31 * 1 + (userId == null ?0 : userId.hashCode());
    第二次循环:result = 31 * result【注:即第一次循环的result】+(userId == null ?0 : userId.hashCode());
    以此类推
    得到整个对象的hash值。


    应用:重写equals方法和hashcode主要使用在Map中,当引用类型为key时,因为key是唯一的,不可重复的,故会比较两个对象是否相等。再判断是覆盖还是新增。

    展开全文
  • 这就是最原始的equals方法,他比较的两个对象的本身的存储地址,例如下面 声明一下,Company这个类并没有重写equals方法,所以Object类它本身比较的是对象的实际地址 接下来再来看看String类的equals方法的源码 ...
  • 一,equals方法的作用:检测一个对象是否等于另一个对象   1)比较两个基本类型的数据的值是否相等。这里是直接比较的值。【错误:基本数据类型没有equals方法】 mark:Java中的基本类型: int,4个字节存储,4...
  • Java Equals方法

    2018-10-16 12:32:45
    Object类中有一个equals方法,该方法是用来检测两个对象是否相等,在Object类中,该方法的实现是对比两个对象的引用是否相等,而非对比内容是否相等,具体的实现如下: public boolean equals(Object obj) { ...
  • 目录为什么需要重写equals方法? 为什么需要重写equals方法? 比方创建一个Student类,定义了一个全参构造方法 public class Student { private String name; private Integer stuId; public Student(String ...
  • string中的equals方法,比较的是对象的内容是否相同 底层实现: public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = ...
  • java equals方法详解

    千次阅读 2019-06-15 17:11:45
    equals方法详解 自定义类对象重写equals方法 一、等于(==)详解 先明确一点:“==” 和equals方法其实都是存储地址的比较 1.在八大基础类型中‘==’ 在基础类型,变量声明赋值其实就是在栈中命名指向常量池...
  • java的equals方法 日期类equals()方法 (Date Class equals() method) equals() method is available in java.util package. equals()方法在java.util包中可用。 equals() method is used to check whether this date...
  • Java equals方法详解

    千次阅读 2018-12-26 11:36:44
    首先equals方法是object类的方法,所有的类都默认继承object类,object类也就是所有类的超类。 如果两个对象进行相等比较,需要调用x.equals(y),但是如果没有重写equals方法,那么默认使用的是object类的equals...
  • java的equals方法 短类equals()方法 (Short class equals() method) equals() method is available in java.lang package. equals()方法在java.lang包中可用。 equals() method is used to check equality or ...
  • equals方法实现

    千次阅读 2017-04-21 19:08:08
    我们一个MyDate类为例,故类中有year,month,day等成员变量,曾经问过equals方法有什么涵义?后来才发现这是一个问题,单连接数据库的时候比较对象的时候它是主角~~~~ 下面我用两种写法equals方法: 方法一: ...
  • java的equals方法 布尔类equals()方法 (Boolean class equals() method) equals() method is available in java.lang package. equals()方法在java.lang包中可用。 equals() method is used to check equality or ...
  • java的equals方法 双类equals()方法 (Double class equals() method) equals() method is available in java.lang package. equals()方法在java.lang包中可用。 equals() method is used to check equality or ...
  • java的equals方法 长类equals()方法 (Long class equals() method) equals() method is available in java.lang package. equals()方法在java.lang包中可用。 equals() method is used to check equality or ...
  • 1.首先我们看看Object类中的equals方法 public boolean equals(Object obj) { return (this == obj); } 我们可以看出Object类中判断的是否是同一个对象,我们接下来来看看下面这个例子 Employee emp1 = new ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 35,412
精华内容 14,164
关键字:

equals方法