面试常问:==和equals的区别(详细详细!!!)

本文阅读 6 分钟
首页 代码,Java 正文

源码分析

        前两天小编去面试了,被问到一个非常基础的问题,==与equals的区别,可小编只是回答了一部分,一个比较基本数据类型,一个是比较引用数据类型,其他的就给忘了,回家之后,小编就百度了一下这个知识点,今天就总结了一下。         我们先来看一段代码:

public static void main(String[] args) { 
        String s1 = "meng";
        String s2 = "meng";
        System.out.print("==的比较结果是:");
        System.out.println(s1==s2);
        System.out.println("equals的比较结果是:"+s1.equals(s2));
    }

img         我们再来看一段代码

public static void main(String[] args) { 
        String s1 = new String("meng");
        String s2 = new String("meng");
        System.out.print("==的比较结果是:");
        System.out.println(s1==s2);
        System.out.println("equals的比较结果是:"+s1.equals(s2));
    }

img         我们看到两次控制台输出的结果不一样,第一次的时候两个都是true,第二次的时候“==”比较的结果是false,“equals”比较的结果是true,这主要是因为双等号在比较引用类型的时候主要是比较地址。

        接下来我们详细说一说==的比较。         当双等号比较的是基本数据类型的时候,比较的数据的值,但是如果比较的是引用数据类型的时候比较的就是数据的内存地址,就比如上面的案例。那为什么上面两个例子比较的结果不同呢?         首先,我们先画图模拟第一种情况。代码“String s1 = ‘meng’”,是jvm现在堆区中的常量池中先创建一个内容为“meng”的地址值,然后再栈去再创建一个S1的变量为其分配一块空间,然后由栈区的S1指向堆内存的“meng”的地址值。而不是直接给S1赋值为meng。         所以,在执行性代码“String s2 = ‘meng’”的时候,会现在堆内存的常量池中查询有没有“meng”的地址,如果没有的话,则会重新分配一块空间,如果有的话,就不会再重新分配一块新的空间了。但是仍然会在栈区重新分配一块空间并命名为“s2”,此时的s2会直接指向常量池中的meng,so,s1和s2指向的是同一个地址值,所以双等号判断会为false。

img         接着,我们再来说一说第二种情况,由上述代码可见,我们是重新new了一下,要记住,只要是new的时候,就会重新创建出一个对象,也就是说jvm会在堆区重新开辟出一块空间内容为“meng”,然后会让s2指向重新开辟的这个地址值,所以,s1和s2的内存地址不一样,所以使用双等号再次比较的时候就会是false了。 img         不知道大家有没有想过,为什么equals方法在比较引用类型的时候就是纯粹的再比较值,而不是比较引用的地址呢?这个得追溯到equals方法的源码了,下面就是我复制过来的源码,以及自己的一点理解。

//我们知道在Java中,所有的类都是直接或者间接的继承Object类,所以这里传入一个Object类型会比较方便一些
public boolean equals(Object anObject) { 
//就是说让s1和s2进行双等号比较,如何二者内存地址相同的话,就会跳出并返回true,如果地址不同,会执行下一个if判断
        if (this == anObject) { 
            return true;
        }
        //instanceof是对传入值的类型的一个判断,即s2若是String类型的话,返回true,继续执行下面代码,如果不是,跳出返回false
        if (anObject instanceof String) { 
        //把s2转化为String类型
            String anotherString = (String)anObject;
            //这里省略了this,n指的是s1的长度
            int n = value.length;
            //判断s1和s2的长度是否相同
            if (n == anotherString.value.length) { 
            //把s1拆分一下,并且把拆分的结果放到v1这个字符数组里,即['m','e','n','g']
                char v1[] = value;
                //同理,把s2拆分放到数组v2里
                char v2[] = anotherString.value;
                int i = 0;
                //将两个数组的值进行比较,如果有一个不同,则返回false
                while (n-- != 0) { 
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

        看完源码我们就知道为什么equals方法是比较引用类型的值了,这是因为底层源码的原因,就感觉,源码很重要。

equals方法的特性

  1. 自反性:对于任何非空引用x来说,比较它本身x.equals(x)都返回true。
  2. 对称性:对于非空引用x、y,x.equals(y)若返回true,那么y.equals(x)也是返回true。
  3. 传递性:对于非空引用x、y、z来说,如果有x.equals(y)返回true,y.equals(z)返回true,那么就有x.equals(z)返回true。
  4. 一致性:对于非空引用x、y,如果x.equals(y)返回true相等的话,那么他们始终保持相等。
  5. 非空性:对于非空引用x,那么x.equals(null)必然会返回false。

        以上就是梦梦对==和equals的一些理解,欢迎大家来分享自己的理解哦,促进学习,哈哈哈。

本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://blog.csdn.net/qq_46540738/article/details/117950219
-- 展开阅读全文 --
安全面试之XSS(跨站脚本攻击)
« 上一篇 07-24

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复