• 源码分析:深入了解 equals、 ==、 hashcode


    引子

    其实很多时候看了博客,学习了相关知识,自己觉得自己懂了
    但是往往又会忘记,因为不清楚真正的底层是如何实现的
    今天,来给大家深入分析下

    ==equals 以及 hashcode

    给出Demo

    case 1

    给出第一个 case1
    大家想一下结果是多少

    // case1
            String s1 = "a" + "b";
            String s2 = new String(s1);
            if(s1==s2) System.out.println("suuu");
            if(s1.equals(s2)) System.out.println("jjjjjj");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    3105
    3105
    jjjjjj
    
    • 1
    • 2
    • 3
    • hashCode() 方法用于返回字符串的哈希码。
    • 字符串对象的哈希码用固定公式计算

    这里的 s1是 new出来的,他们的hashcode是相同的;

    给出第一个结论

    hashCode()方法常被设计用来提高性能,其两者的关系在于:
    ①若两个对象相等(equals),那么这两个对象一定有相同的哈希值(hashCode);
    ②若两个对象的哈希值相同,但这两个对象并不一定相等。
    
    • 1
    • 2
    • 3

    case 2

         String s5 = "es";
         String s6 = new String("es");
         System.out.println("-----------");
         System.out.println(s5.hashCode());
         System.out.println(s6.hashCode());
         System.out.println(s5==s6);
         System.out.println(s5.equals(s6));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    -----------
    3246
    3246
    false
    true
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里的 == 就是 判断出 包装类String的引用地址不同

            System.out.println("-----------");
            String s3 = "es";
            String s4 = "es";
            System.out.println(s3.hashCode());
            System.out.println(s4.hashCode());
            System.out.println(s3==s4);
            System.out.println(s3.equals(s4));
            s3 = "123";
            System.out.println("s3" + s3);
            System.out.println("s4" + s4);
            System.out.println(s3.hashCode());
            System.out.println(s4.hashCode());
            System.out.println(s3==s4);
            System.out.println(s3.equals(s4));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    -----------
    3246
    3246
    true
    true
    s3123
    s4es
    48690
    3246
    false
    false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里,由于s3和s4同时定义,
    于是jvm直接让两个引用指向了一个地址
    这里地址相同,值相同,直接返回true

    • equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。

    case 3

    首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:

    class Cat {
        public Cat(String name) { this.name = name; }
        private String name; public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }
    
    class testDomeOne1 {
        public static void main(String[] args) {
            Cat c1 = new Cat("星期五");
            Cat c2 = new Cat("星期五");
            System.out.println(c1.equals(c2));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    false
    
    • 1

    所以,重写toString方法

    class Cat {
        public Cat(String name) { this.name = name; }
        private String name; public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    
        @Override
        public String toString() {
            return "Cat{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    
    class testDomeOne1 {
        public static void main(String[] args) {
            Cat c1 = new Cat("星期五");
            Cat c2 = new Cat("星期五");
            System.out.println(c1.toString());
            System.out.println(c2.toString());
            System.out.println(c1.hashCode());
            System.out.println(c2.hashCode());
            System.out.println(c1==c2);
            System.out.println(c1.toString().equals(c2.toString()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    Cat{name='星期五'}
    Cat{name='星期五'}
    1846274136
    1639705018
    false
    true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    源码分析

    equals

        public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            //这里还是判断的==
            //但是下面增加了一个操作
            //将String转为了char[]
           /** public final class String
        implements java.io.Serializable, Comparable, CharSequence {
        private final char value[];
      */ 
         if (anObject instanceof String) {
                String anotherString = (String)anObject;
                int n = value.length;
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                            return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }
    
    
    //instanceof 是 Java 的保留关键字。. 它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    hashcode

    没啥好讲的,就是这么简单

        public int hashCode() {
            int h = hash;
            if (h == 0 && value.length > 0) {
                char val[] = value;
    
                for (int i = 0; i < value.length; i++) {
                    h = 31 * h + val[i];
                }
                hash = h;
            }
            return h;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    全部代码

    class testDomeOne{
    
        public static void main(String[] args) {
    // case1
            String s1 = "a" + "b";
            String s2 = new String(s1);
            if(s1==s2) System.out.println("suuu");
            //==设计的目的就是为比较两个对象是否是同一个对象。
            //比较对象的相等不仅要比较对象内容相等,还要比较对象引用地址是否相等。
            if(s1.equals(s2)) System.out.println("jjjjjj");
    
            //==比较的是两个对象是否是同一个对象,这并不能满足很多需求。
            // 有时候当两个对象不==的时候,我们仍然会认为两者是“相等”的,
            // 比如对于String对象,当两个对象的字符串序列是一致的,我们就认为他们是“相等”的。
            // 对于这样的需求,需要equals()来实现。记得重写 toString
    // case2
    
            String s3 = "es";
            String s4 = "es";
            System.out.println("-----------");
            System.out.println(s3.hashCode());
            System.out.println(s4.hashCode());
            System.out.println(s3==s4);
            System.out.println(s3.equals(s4));
            //hashCode()方法返回的是一个数值,称之为hashCode。hashCode()方法在Object类中的定义如下
            //①若两个对象相等(equals),那么这两个对象一定有相同的哈希值(hashCode);②若两个对象的哈希值相同,但这两个对象并不一定相等。
    // case3
            String s5 = "es";
            String s6 = new String("s5");
            System.out.println("-----------");
            System.out.println(s5.hashCode());
            System.out.println(s6.hashCode());
            System.out.println(s5==s6);
            System.out.println(s5.equals(s6));
    
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
  • 相关阅读:
    微信小程序中使用Behavior混入
    C++数据结构和算法 01
    java 把a.txt文件中的内容复制到当前项目目录下的b.txt文件中,2种方式比较复制效率 毫秒比较
    Linux 下安装 miniconda,管理 Python 多环境
    Loss模块
    【ML01】Linear Regression with One Variable
    ClickHouse 对付单表上亿条记录分组查询秒出, OLAP应用秒杀其他数据库
    官宣!Wayland正式支持基于IntelliJ的IDE
    学习笔记|矩阵按键控制原理|数值转化为键码|密码锁|STC32G单片机视频开发教程(冲哥)|第十四集:矩阵按键原理及实践
    【Linux】awk入门
  • 原文地址:https://blog.csdn.net/futurn_hero/article/details/126783153