摘要:文主要介绍了JAVA语言的Object 类,它是所有类的父类,Object类中定义了很多重要的方法,有些基础方法是必须要搞清楚的,今天我们就来学习下Object类中的equals方法和hashCode方法。让我们在JAVA语言中走的更远。
Object 类是所有类的父类,Object类中定义了很多重要的方法,有些基础方法是必须要搞清楚的,今天我们就来学习下Object类中的equals方法和hashCode方法。
一、equals方法
首先我们来看下Object类的equals方法的源码:
Java代码
1. public boolean equals(Object obj) { 2. return (this == obj); 3. }
很明显它是比较两个对象的引用(即内存地址)是否相等。如果你不知道这个,想当然的以为它比较的是内容,比如我们要比较两个用户对象是否相等:
User实体类:
Java代码
1. public class User { 2. 3. private int userId; 4. private String userName; 5. private int age; 6. 7. public User(int userId, String userName, int age) { 8. this.userId = userId; 9. this.userName = userName; 10. this.age = age; 11. } 12. 13. public int getUserId() { 14. return userId; 15. } 16. public void setUserId(int userId) { 17. this.userId = userId; 18. } 19. public String getUserName() { 20. return userName; 21. } 22. public void setUserName(String userName) { 23. this.userName = userName; 24. } 25. public int getAge() { 26. return age; 27. } 28. public void setAge(int age) { 29. this.age = age; 30. } 31. }
测试代码:
Java代码
1. public class UserTest { 2. 3. public static void main(String[] args) { 4. User u1 = new User(1, "z3", 25); 5. User u2 = new User(1, "z3", 25); 6. boolean b = u1.equals(u2); 7. System.out.println(b); 8. } 9. 10. }
执行结果为:false,为什么呢,因为你调用的是Object类的equals方法,它比较的是两个对象的引用,即内存地址,在Java虚拟机的堆上是两块独立的内存空间,绝对不相等的。并不是我们想要的结果,那应该要怎么做呢?自己重写Object类的equals方法就好了:
我们在User实体类中添加equals方法:
Java代码
1. @Override 2. ublic boolean equals(Object obj) { 3. if (obj == null) 4. return false; 5. if(obj instanceof User) { 6. User other = (User) obj; 7. if (age != other.age) 8. return false; 9. if (userId != other.userId) 10. return false; 11. if (userName == null) { 12. if (other.userName != null) 13. return false; 14. } else if (!userName.equals(other.userName)) 15. return false; 16. } 17. return true;
再次执行测试代码,结果为:true
我们可以看到重写的equals方法,比较了User类的每一个成员变量,那成员变量之间怎么比较呢,如果是基本数据类型如int,float,double,boolean等,直接比较其值就行了。
如果是字符串,直接调用字符串的equals方法即可,因为String类帮我们重写了equals方法,我们来看它的源码:
Java代码
1. public boolean equals(Object anObject) { 2. if (this == anObject) { 3. return true; 4. } 5. if (anObject instanceof String) { 6. String anotherString = (String)anObject; 7. int n = value.length; 8. if (n == anotherString.value.length) { 9. char v1[] = value; 10. char v2[] = anotherString.value; 11. int i = 0; 12. while (n-- != 0) { 13. if (v1[i] != v2[i]) 14. return false; 15. i++; 16. } 17. return true; 18. } 19. } 20. return false; 21. }
可以看出String类的eqauls方法比较的是每一个char字符。其实查看Jdk源码,可以发现,各基本数据类型的包装类如Integer,Float,Double,Boolean等都重写了Object类的equals方法。因为实际业务需要我们去比较对象或变量的内容而不是引用。
二、hashCode方法
Object类的hashCode方法源码如下:
Java代码
1. public native int hashCode();
它是一个本地方法,返回一个int类型的整数。
Java为每一个对象提供一个int类型的hashCode,其目的是快速查找定位对象,猜测啊,在底层有一张Hash表,存储对象的hashCode和内存地址的映射,这样方便JVM在内存中能够快速查找定位到某个对象,不然,内存中那么多的对象,JVM如何查找一个对象呢。
hashCode有几个重要特性:
1.hashCode是为了查找对象或元素提高性能
2.如果两个对象equals相等,那么两个对象的hashCode一定相等
3.如果两个对象的hashCode相等,两个对象的equals不一定相等
4.如果要重写对象的equals方法,尽量要重写对象的hashCode方法
接下来,我们一一说明:
第1点,hashCode是为了查找对象或元素提高性能,这在上面已经说了JVM要查找内存中的对象可以快速定位。还有就是集合类的实现,比如Set集合,元素不允许重复,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。于是采用Java的哈希表原理,先根据元素的hashCode定位元素位置,如果该位置元素不存在,则将元素插入集合的该位置,如果已经存在,则equals比较其内容,如果内容一致则元素重复了,否则采用链式数据结构存储到该位置(HashMap的实现)。
第2点,如果两个对象equals相等,那么两个对象的hashCode一定相等。这个上面的Set集合就已经解释了,如果两个对象equals相等,hashCode不相等,那么根据Set集合实现会将两个元素存储到不同的位置,那么这就违背Set集合元素不允许重复了。
第3点,如果两个对象的hashCode相等,两个对象的equals不一定相等。这个我们看下Set的实现HashSet,其底层是HashMap的实现:
Java代码
1. public V put(K key, V value) { 2. if (key == null) 3. return putForNullKey(value); 4. int hash = hash(key.hashCode()); 5. int i = indexFor(hash, table.length); 6. for (Entry<K,V> e = table[i]; e != null; e = e.next) { 7. Object k; 8. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 9. V oldValue = e.value; 10. e.value = value; 11. e.recordAccess(this); 12. return oldValue; 13. } 14. } 15. 16. modCount++; 17. addEntry(hash, key, value, i); 18. return null; 19. }
根据HashMap的put方法实现,我们可以看到首先根据key的hashCode计算出元素在哈希表的位置,如果该位置上已经有元素(说明这两元素的hashCode相等),再equals比较两元素的内容,如果不相等,则以链表的方式将两元素存储在该位置,这充分说明了两元素hashCode相等,但equals不一定相等。
第4点,如果要重写对象的equals方法,尽量要重写对象的hashCode方法,这个其实就是保证第2点的实现,如果不重写hashCode方法,还是以Set集合为例,就无法保证元素不重复。可以查看jdk源码,像String类,Integer类等只要重写了equals方法的,都重写了hashCode方法。
总结,我们在开发中,养成良好的习惯,每写一个实体类,就重写它的equals方法和hashCode方法,要么都不写,要写两个都要写,可以减少不必要的问题发生。
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言JAVA频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号