==和equals的区别?你知道吗?

版权声明:本文为博主原创文章,转载请注明出处! https://blog.csdn.net/sinat_33921105/article/details/82468623

对于==和equals我相信,当自己还是小白的时候是比较容易搞混两者的区别的,以至于会出现一些小错误,从而导致解决不了的问题,所以作为基础知识的一个点,我们很有必要弄清楚这两者的区别!

庆哥: 小白,你知道==和equals的区别?

小白: 这两个啊,你还别说,我记得之前我就因为这个问题出现过一个错误,当时好像要判断一个字符串是否和指定的字符串相等,记得当时是使用了==,可是就是得不到自己想要的结果,后来查了资料才发现我那个情境下应该使用equals。

庆哥: 是的,如果不注意这两者的区别,还真的会出现一些错误,那么你现在知道两者的区别了吗?

小白: 这个。。。因为那是很早的时候查的资料,最近也没有使用过,还真有点忘记了呢?

庆哥: 哈哈,要记得经常回顾以往的旧知识啊,不然学着新的忘着旧的,其实学校效率也不高哦。

小白: 谁说不是呢?看来我该找个时间整理一下之前的笔记了,对了,不如庆哥给我出个这方面的题吧,我看看自己是不是真的忘记了?

庆哥: 那好啊,你看看下面这道题

   String s = new String("hello");
        String s1 = "hello";

        System.out.println(s == s1);
        System.out.println(s.equals(s1));


        System.out.println(s == null);
        System.out.println(s.equals(""));

你说这些代码执行的输出结果是什么呢?

小白: 让我看看,这是字符串相关,s和s1都是创建字符串对象,对于s1肯定是在字符串常量池中创建“hello”这个字符串对象,然后s1是个引用指向这个对象,那么对于s呢?里面也是“hello”这个字符串,也是放在字符串常量池中,那么s和s1是不是相等呢?不行,第一个的输出结果我都不知道是什么了,晕了

庆哥: 别晕,别晕,千万别晕,还没开始呢?怎么能晕呢?你这里是因为对这行代码的创建过程不是很理解

String s = new String("hello");

你知道这行代码究竟是如何执行,如何创建的吗?

小白: 不行,这个真的不知道

庆哥: 还记得我们之前说过嘛,只有编译期确定下来的字符串才会放到字符串常量池中,而在编译期无法确定需要等到运行期才能确定的则不会被放在字符串常量池中,那么简单来说,什么是编译期就能确定的,说白了就是一看就是个字符串,使用双引号括起来的字符串,比如这里的“hello”,我们一看就是字符串啊,所以对于上面的代码,jvm首先会从字符串常量池中检查是否存在“hello”这个字符串,如果不存在,那就在字符串常量池中创建“hello”这个字符串对象,然后就是执行“newString(“hello”)”了,这个时候不要被里面的“hello”字符串给迷惑了,它已经在字符串常量池中创建了,这个时候要执行的是new的操作,这个在编译期是无法判断new出来的字符串是什么,必须等到运行阶段才能确定是“hello”,所以这个时候其实是在堆内存中创建了一个新的字符串对象“hello”,而引用s也同时指向堆内存中的这个“hello”了。

当然,如果字符串常量池中已经存在“hello”的话则不会再次创建,但是在堆内存中依然会新创建一个“hello”对象,并且将引用赋给s。

小白: 你这么一说,感觉对这行代码理解的非常透彻啊,那么现在这个问题就是==和equals的区别了吧?

庆哥: 嗯,理解了这个问题,我们下一步的重点就是看看==和equals的区别了,首先我们知道这两个都是用来比较的,那么比较什么呢?

基本数据类型的比较

首先,如果你比较的是基本数据类型的话,那一定是使用==,举个例子,比如这样

int a = 5;
        int b = 5;
        System.out.println(a == b);

就是比较两个数组是否相等,那你知道为啥一定用==吗?

小白: 这个,这个。。。为啥?

庆哥: 为啥?因为equals是函数啊,而基本数据类型根本不是对象啊,怎么能用函数呢?

小白: 好吧好吧,突然蒙圈了

庆哥: 所以我们一般讨论==和equals的时候几乎不讨论基本数据类型,大多数都是在说引用数据类型的比较

引用数据类型的比较

所以我们的重点应该也是放在引用数据类型的比较,这里我们依然来拿字符串进行举例,我们再看这个

String s = new String("hello");
        String s1 = "hello";

我们已经知道这里的s和s1所指向的内存地址是不同的,然后我们来看一下代码的执行结果

  String s = new String("hello");
        String s1 = "hello";

        System.out.println(s == s1);
        System.out.println(s.equals(s1));

执行结果是

image

从结果我们可以看出,对于==的比较,两者是false,这说明什么呢?

小白: 这是不是说明对于引用数据类型,==比较的是他们的引用的地址是否一样。

庆哥: 是的,对于==比较的是引用数据类型的引用是否相等,也就是所指向的内存地址是否一样,这里我们知道s所指向的内存地址是在堆内存中的,而s1是在字符串常量池中的,虽然指向的字符串内容都是“hello”,可是地址是不同的。

小白: 那我知道了,对于equals就是比较引用地址所指向的内存地址锁对应的内容是否一致的,也就是说==比较内存地址,而equals比较内存地址指向的内容是否一样!

庆哥: 可以可以,你总结的很不错啊,另外我们再看一点,就是这个equals方法其实是Object中的一个函数,默认是这样的

public boolean equals(Object obj) {
    return (this == obj);
}

小白: 这里面也使用了==啊。

庆哥: 是的,默认的equals方法也是使用了==,所以一般这个equals是由我们去覆写的,如果不覆写,那其实跟==没什么区别。

小白: 那这里的字符串中的equals是不是就重写了

庆哥: 是的,String类就覆写了这个方法,从而达到比较地址所指向的内容是否一致

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = offset;
            int j = anotherString.offset;
            while (n-- != 0) {
                if (v1[i++] != v2[j++])
                    return false;
            }
            return true;
        }
    }
    return false;
}

小白: so ge xi nai,明白了!

猜你喜欢

转载自blog.csdn.net/sinat_33921105/article/details/82468623