高薪程序员&面试题精讲系列10之String类中equals方法的底层是怎么实现的?

一. 面试题及剖析

1. 今日面试题

每日一题,请跟着 壹哥 开始今天的面试题吧!

请问String类中equals方法的底层是怎么实现的?

说说equals()与==的区别?

2. 题目剖析

上面这个题目,其实考察的还是我们对String类的掌握情况,尤其是对String中两个字符串是否相等的判断,但是这个题目又结合了对Object类中equals()方法的理解。我们看到这个题目,只要打开String类中的equals()方法的源码,就可以得出答案。

二. 佐证案例

1. 代码案例

在讲解今天这个题目的答案之前,我们先来看一段代码,如果我不先给你答案,你能准确说出这几行代码的执行结果吗?

public static void main(String[] args) {
    //地址相同
    String s1 = "hello world";
    String s2 = "hello world";
    System.out.println("s1==s2 : " + (s1 == s2));//true
    System.out.println("s1.eqauls(s2) : " + s1.equals(s2));//true

    //地址不同
    String s3 = new String("yiyige");
    String s4 = new String("yiyige");
    System.out.println("s3==s4 : " + (s3 == s4));//false
    System.out.println("s3.equals(s4) : " + s3.equals(s4));//true

    //地址不同
    String s5 = "syy";
    String s6 = new String("syy");
    System.out.println("s5==s6 : " + (s5 == s6));//false
    System.out.println("s5.eqauls(s6) : " + s5.equals(s6));//true
}

2. 执行结果

好了,我们看看上面这段代码的执行结果,和你预想的结果一样吗?如果一样,说明你的String掌握的很6了,如果有错误,说明你还要再努力啦......

高薪程序员&面试题精讲系列10之String类中equals方法的底层是怎么实现的?

这时候,大家可以结合 壹哥 前面讲解的另外两篇关于String的面试题文章:

《String s=new String("xyz")中产生了几个对象》

《String为什么不可变》

如果你前面仔细看过这两篇文章,其实就可以明白上面的代码为什么是这样的结果了。但是今天我们可以结合String类中的equals()方法,从equals()方法的底层源码角度来进行分析。而且弄明白了equals()方法之后,我们也可以回答另一个面试题,即:请说一下equals()与==的区别。

三. 参考答案

执行完上面的代码案例之后,我们得到了对应的执行结果,但是为什么是这个结果呢?我们来看看String类中equals()方法的底层源码是怎么实现的吧。

1. 底层源码

String类中equals()方法的源码如下:

/**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        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;
    }

2. 源码分析

我们从上面的源码注释上就可以知道,equals()方法就是用于判断两个字符串是否相同的。但是这个equals()方法对两个字符串是否相同的判断,是根据两个条件进行的,即:

  1. 两个对象的地址是否向相同;
  2. equals()方法的参数是不是String类或其父类创建的对象。

2.1 第1个if判断

在equals方法的第一个if判断中,主要是根据"=="符号来判断两个对象的地址是否相同,如果两个对象的地址相同,则直接返回true。比如s1.equals(s2),就在第1个if判断中直接返回true了。

2.2 第2个if判断

在第2个if判断中,出现了instanceof这样的语句,“anObject instanceof String”实际上就是判断,该向上转型的对象是不是String的子类或同类,只有是String类型才进行比较。实际上就是判断在上转型之前的那个类型是不是String类型,如果不是,则返回false。

如果两个对象都是String类型,则将anObject对象下转型为String类型,然后定义 一个变量n 用来获取value字符数组的长度,我们知道value字符数组中存储的就是当前字符串的字符内容,再接着判断当前字符串的长度与anObject字符串的长度是否相等,因为只有相同才有可能是相同的字符。如果两个字符串的长度不同,这时也会return false。

如果两个字符串的长度相同,则进行下一步判断,进入while循环,一个一个的比较两个字符数组中的字符元素是否相同。如果相同,返回true,如果不同,则返回false。

3. 代码执行分析

我们分析完了equals()方法的源码之后,再结合上面的代码案例,对每一步的执行结果分析一下:

s1==s2:我们知道"=="是用于判断两个对象的地址是否相同的,根据前文可知,s1与s2的地址肯定相同,所以结果为true;

s1.equals(s2):因为s1与s2的地址相同,则在equals()方法的第1个判断中就直接返回true;

s3==s4:因为s3和s4是两个不同的String对象,地址不同,所以结果为false;

s3.equals(s4):在这里会判断s4是否是String类或其子类,然后判断s3与s4对应的字符串内容是否相同,这里s3与s4的地址虽然不同,但是字符串内容相同,所以也是返回true;

s5==s6:两个字符串的地址不同,直接返回false;

s5.equals(s6):最终还是会比较两个字符串的内容是否相同,地址虽然不同,但内容是相同的,所以结果为true。

四. 结论

经过本文的分析,我们就探究了String类中equals()方法的底层源码,明白了其底层执行逻辑,再结合上述案例代码,所以就可以得出如下结论:

String类中equals方法用于比较的两个字符串是否相同。如果两个字符串的地址相同,则直接返回true;如果两个字符串的地址不同,则进一步判断字符串的内容是否相同,字符串内容完全相同,也会返回true。

 

上一篇:如何用jq库实现反选和全选;


下一篇:实战:Keepalived 高可用LVS-主备模式