1:== 与 equals()(重要)

  1. == : 它的作用是判断两个对象的地址是不是相等
  2. 判断两个对象是不是同一个对象(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)。
  3. equals() : 它的作用也是判断两个对象是否相等。
  4. 两种使用情况:
  5. 情况 1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
  6. 情况 2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法判断来两个对象的内容相等;
  7. 若它们的内容相等,则返回 true (即,认为这两个对象相等)。
  8. 注意:Stringequal方法时经过重写的
  1. //String中重写的euqals方法
  2. public boolean equals(Object anObject) {
  3. if (this == anObject) {
  4. return true;
  5. }
  6. if (anObject instanceof String) {
  7. String anotherString = (String)anObject;
  8. int n = value.length;
  9. if (n == anotherString.value.length) {
  10. char v1[] = value;
  11. char v2[] = anotherString.value;
  12. int i = 0;
  13. while (n-- != 0) {
  14. if (v1[i] != v2[i])
  15. return false;
  16. i++;
  17. }
  18. return true;
  19. }
  20. }
  21. return false;
  22. }

2:hashCode()介绍

  1. hashCode()在散列表中才有用,在其它情况下没用。
  2. 在散列表中 hashCode() 的作用是获取对象的哈希码(散列码),进而确定该对象在散列表中的位置。
  3. hashCode() 的作用是获取哈希码,也称为散列码;
  4. 它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
  5. hashCode() 定义在 JDK Object.java 中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。
  6. 散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。
  7. 以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode
  8. 当你把对象加入 HashSet 时,
  9. HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较;
  10. 如果没有相符的 hashcodeHashSet 会假设对象没有重复出现。
  11. 如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。
  12. 如果两者相同,HashSet 就不会让其加入操作成功。
  13. 如果不同的话,就会重新散列到其他位置。

3:hashCode()与 equals()

  1. 对于hashCode()与 equals()的关系 需要分两种情况讨论
  2. 第一种 不会创建“类对应的散列表”
  3. 这里所说的“不会创建类对应的散列表”是说:
  4. 我们不会 不会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中 使用 hashCode()
  5. equals() 用来比较该类的两个对象是否相等。
  6. hashCode() 则根本没有任何作用,所以,不用理会hashCode()。
  1. import java.util.*;
  2. import java.lang.Comparable;
  3. public class NormalHashCodeTest{
  4. public static void main(String[] args) {
  5. // 新建2个相同内容的Person对象,
  6. // 再用equals比较它们是否相等
  7. Person p1 = new Person("eee", 100);
  8. Person p2 = new Person("eee", 100);
  9. Person p3 = new Person("aaa", 200);
  10. System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
  11. System.out.printf("p1.equals(p3) : %s; p1(%d) p3(%d)\n", p1.equals(p3), p1.hashCode(), p3.hashCode());
  12. }
  13. private static class Person {
  14. int age;
  15. String name;
  16. public Person(String name, int age) {
  17. this.name = name;
  18. this.age = age;
  19. }
  20. /**
  21. * @desc 覆盖equals方法
  22. */
  23. public boolean equals(Object obj){
  24. if(obj == null){
  25. return false;
  26. }
  27. //如果是同一个对象返回true,反之返回false
  28. if(this == obj){
  29. return true;
  30. }
  31. //判断是否类型相同
  32. if(this.getClass() != obj.getClass()){
  33. return false;
  34. }
  35. Person person = (Person)obj;
  36. return name.equals(person.name) && age==person.age;
  37. }
  38. }
  39. }
  40. //p1.equals(p2) : true; p1(1169863946) p2(1901116749)
  41. //p1.equals(p3) : false; p1(1169863946) p3(2131949076)
  1. 第二种 会创建“类对应的散列表”
  2. 这里所说的“会创建类对应的散列表”是说:
  3. 我们会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中
  4. 如果两个对象相等,则 hashcode 一定也是相同的;
  5. 两个对象相等,对两个对象分别调用 equals 方法都返回 true;
  6. 两个对象有相同的 hashcode 值,它们也不一定是相等的(不同的对象也可能产生相同的 hashcode,哈希冲突);
  7. 在这种情况下,除了要覆盖equals()之外,也要覆盖hashCode()函数
  8. hashCode() 的默认行为是对堆上的对象产生独特值。
  9. 如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
  1. public class ConflictHashCodeTest{
  2. public static void main(String[] args) {
  3. // 新建Person对象,
  4. Person p1 = new Person("eee", 100);
  5. Person p2 = new Person("eee", 100);
  6. Person p3 = new Person("EEE", 100);
  7. // 新建HashSet对象
  8. HashSet set = new HashSet();
  9. set.add(p1);
  10. set.add(p2);
  11. set.add(p3);
  12. // 比较p1 和 p2, 并打印它们的hashCode()
  13. System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
  14. // 比较p1 和 p3, 并打印它们的hashCode()
  15. System.out.printf("p1.equals(p4) : %s; p1(%d) p4(%d)\n", p1.equals(p3), p1.hashCode(), p3.hashCode());
  16. // 打印set
  17. System.out.printf("set:%s\n", set);
  18. }
  19. private static class Person {
  20. int age;
  21. String name;
  22. public Person(String name, int age) {
  23. this.name = name;
  24. this.age = age;
  25. }
  26. /**
  27. * @desc重写hashCode
  28. */
  29. @Override
  30. public int hashCode(){
  31. int nameHash = name.toUpperCase().hashCode();
  32. return nameHash ^ age;
  33. }
  34. /**
  35. * @desc 覆盖equals方法
  36. */
  37. @Override
  38. public boolean equals(Object obj){
  39. if(obj == null){
  40. return false;
  41. }
  42. //如果是同一个对象返回true,反之返回false
  43. if(this == obj){
  44. return true;
  45. }
  46. //判断是否类型相同
  47. if(this.getClass() != obj.getClass()){
  48. return false;
  49. }
  50. Person person = (Person)obj;
  51. return name.equals(person.name) && age==person.age;
  52. }
  53. }
  54. }
  55. //p1.equals(p2) : true; p1(68545) p2(68545)
  56. //p1.equals(p3) : false; p1(68545) p3(68545)
  57. // 比较p1和p2,我们发现:它们的hashCode()相等,通过equals()比较它们也返回true。所以,p1和p2被视为相等。
  58. //因此p1 set进去后 p2不能set进去
  59. //比较p1和p3,我们发现:虽然它们的hashCode()相等;但是,通过equals()比较它们返回false。所以,p1和p3被视为不相等。
  60. //因此p1 set进去后 p3还能set进去

4:== 与 equal 与 hashcode 总结

  1. == :基本数据类型的值 引用数据类型地址
  2. equal:没被重写 判断逻辑 与== 一致
  3. 被重写判 判断逻辑 为判断内容
  4. hashcode :经过hash 运算生成的值
  5. 1hashcode不经过重写完全没意义
  6. 2:如果不是 之后使用在HashSet, Hashtable, HashMap hashcode值完全没意义
  7. 3:在hashcode 经过重写 并且 在之后使用在HashSet, Hashtable, HashMap
  8. 如果是则hashcode一致 内容不一定完全相等 对象也就不一定相等(哈希运算算法 字母大写(换小写) 字母小写)
  9. 在通过重写的equal比较 如果还是一致 对象才一定相等
  10. 通常在hash表中会先进行 hashcode的比较(更快) 再进行equal的比较