再也不要对java中==和equals的区别有困惑了,这篇文章保证你能懂

简介: 想到你应该无数次看到过这个问题了,也可能你已经看过无数篇文章了,如果你还是一头雾水或者是不理解,那试着看看这篇文章,相信你一定能看懂。

一、理解”==“的含义


在java中,主要有两个作用。


1、基础数据类型:比较的是他们的值是否相等,比如两个int类型的变量,比较的是变量的值是否一样。

2、引用数据类型:比较的是引用的地址是否相同,比如说新建了两个User对象,比较的是两个User的地址是否一样。


OK。到这就注意了,你会发现,我在举引用的例子的时候,使用的是User对象,而不是String。别着急接着往下看。


二、理解equals的含义


先看看他的源码,equals方法是在Object中就有。注意了这里的源码是Object里面的equals。

/*
     * @param   obj   the reference object with which to compare.
     * @return  {@code true} if this object is the same as the obj
     *          argument; {@code false} otherwise.
     * @see     #hashCode()
     * @see     java.util.HashMap
     */
    public boolean equals(Object obj) {
        return (this == obj);
    }

从这个源码中你会发现,比较的是当前对象的引用和obj的引用是否相同,也就是说比较的默认就是地址。还记的在上面我们使用的是User而不是String嘛?在这里==比较的是引用的地址,equals也是比较的是引用的地址,所以他们的效果在这里是一样的。

public class StringDemo {
    public static void main(String args[]) {
        int a=1;
        int b=1;
        System.out.println(a == b);    //  true
        User user1 = new User();
        User user2 = new User();
        //此时使用的是普通对象User
        //所以==和equals的作用是一样的。
        System.out.println(user1 == user2);      //  flase
        System.out.println(user1.equals(user2));  //  flase
    }
}

现在你会发现好像equals的作用和==没什么区别呀,那String类型那些乱七八糟的东西是什么呢?继续往下看马上揭晓。


三、重写equals


1、String中equals方法


看到这个标题相信你已经能找到答案里,Object对象里面的==和equals没有什么区别,这样一看equals方法存在的意义真的不大,不过后来String在Object的基础之上重写了equals,于是功能被大大的改变了。如何重写的呢?我们去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;
    }

从上面的源码,我们能够获取到的信息是:String中的equals方法其实比较的是字符串的内容是否一样。也就是说如果像String、Date这些重写equals的类,你可要小心了。使用的时候会和Object的不一样。


2、测试String


看看下面的代码:

public class StringDemo {
    public static void main(String args[]) {
        String str1 = "Hello";
        String str2 = new String("Hello");
        String str3 = str2; // 引用传递
        System.out.println(str1 == str2); // false
        System.out.println(str1 == str3); // false
        System.out.println(str2 == str3); // true
        System.out.println(str1.equals(str2)); // true
        System.out.println(str1.equals(str3)); // true
        System.out.println(str2.equals(str3)); // true
    }
}

在上面的代码中,定义了三个字符串,分别使用==和equals去比较。为什么会出现这样一个结果呢?还需要从内存的角度来解释一下。


3、内存解释


在java中我们一般把对象存放在堆区,把对象的引用放在栈区。因此在上面三个字符串的内存状态应该是下面这样的。

v2-d4a296b5f342d99e975b5e453b0593d7_1440w.jpg

现在明白了吧。


(1)String str1 = "Hello"会在堆区存放一个字符串对象

(2)String str2 = new String("Hello")会在堆区再次存放一个字符串对象

(3)String str3 = str2这时候Str3和Str2是两个不同的引用,但是指向同一个对象。


根据这张图再来看上面的比较:


(1)str1 == str2嘛?意思是地址指向的是同一块地方吗?很明显不一样。

(2)str1 == str3嘛?意思是地址指向的是同一块地方吗?很明显不一样。

(3)str2 == str3嘛?意思是地址指向的是同一块地方吗?很明显内容一样,所以为true。

(4)str1.equals(str2)嘛?意思是地址指向的内容一样嘛?一样。

(4)str1.equals(str3)嘛?意思是地址指向的内容一样嘛?一样。

(4)str2.equals(str3)嘛?意思是地址指向的内容一样嘛?一样。

OK。现在不知道你能理解嘛?


4、总结:


1)、基础类型比较

使用==比较值是否相等。

(2)、引用类型比较

①重写了equals方法,比如String。

第一种情况:使用==比较的是String的引用是否指向了同一块内存

第二种情况:使用equals比较的是String的引用的对象内用是否相等。

②没有重写equals方法,比如User等自定义类

==和equals比较的都是引用是否指向了同一块内存。


5、一个小问题


当然了,String类型到这还没结束,有一个小问题需要大家注意一下。比如看下面的代码:

public class ObjectDemo{
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = new String("Hello");
        s2 = s2.intern();
        System.out.println(s1 == s2);       //  true
        System.out.println(s1.equals(s2));  //  true
    }
}

在这里多了一个intern方法。他的意思是检查字符串池里是否存在,如果存在了那就直接返回为true。因此在这里首先s1会在字符串池里面有一个,然后 s2.intern()一看池子里有了,就不再新建了,直接把s2指向它。

相关文章
|
1天前
|
缓存 Java 数据库连接
java面试题目 强引用、软引用、弱引用、幻象引用有什么区别?具体使用场景是什么?
【6月更文挑战第28天】在 Java 中,理解和正确使用各种引用类型(强引用、软引用、弱引用、幻象引用)对有效的内存管理和垃圾回收至关重要。下面我们详细解读这些引用类型的区别及其具体使用场景。
10 3
|
9天前
|
Java
Java中Comparable接口和Comparator接口的区别(如果想知道Java中Comparable接口和Comparator接口的区别,那么只看这一篇就足够了!)
Java中Comparable接口和Comparator接口的区别(如果想知道Java中Comparable接口和Comparator接口的区别,那么只看这一篇就足够了!)
|
12天前
|
存储 安全 Java
Java Queue:从入门到精通,一篇文章就够了!
【6月更文挑战第18天】Java集合框架中的队列Queue遵循FIFO原则,用于存储和管理元素。从创建队列(如LinkedList示例)到移除元素(remove和poll方法),再到不同实现类(如ArrayDeque和ConcurrentLinkedQueue),队列在多线程、任务调度等场景中广泛应用。自定义队列如LimitedQueue展示如何限制容量。了解并熟练使用队列能提升程序性能和可读性。队列,是高效编程的关键工具。
|
13天前
|
安全 Java 索引
Java List:从入门到精通,一篇文章就够了!
【6月更文挑战第17天】Java List是有序元素集合,支持索引访问、添加、删除和修改。从ArrayList、LinkedList到Vector,各种实现满足不同场景需求。使用add()添加元素,get()获取,set()修改,remove()删除。遍历可用for-each或Iterator,subList()创建子集。注意线程安全,可选synchronizedList()、Vector或CopyOnWriteArrayList。理解List的基本操作和特性,能提升编程效率。
|
2天前
|
缓存 NoSQL Java
Redis系列学习文章分享---第四篇(Redis快速入门之Java客户端--商户查询缓存+更新+双写一致+穿透+雪崩+击穿+工具封装)
Redis系列学习文章分享---第四篇(Redis快速入门之Java客户端--商户查询缓存+更新+双写一致+穿透+雪崩+击穿+工具封装)
6 0
|
2天前
|
存储 NoSQL Java
Redis系列学习文章分享---第三篇(Redis快速入门之Java客户端--短信登录+session+验证码+拦截器+登录刷新)
Redis系列学习文章分享---第三篇(Redis快速入门之Java客户端--短信登录+session+验证码+拦截器+登录刷新)
4 0
|
2天前
|
存储 NoSQL Java
Redis系列学习文章分享---第二篇(Redis快速入门之Java客户端--Jedis+连接池+SpringDataRedis+RedisTemplate+RedisSerializer+Hash)
Redis系列学习文章分享---第二篇(Redis快速入门之Java客户端--Jedis+连接池+SpringDataRedis+RedisTemplate+RedisSerializer+Hash)
6 0
|
3天前
|
Java
Java中代码块区别及代码示例
Java中代码块区别及代码示例
|
3天前
|
XML 安全 Java
一篇文章讲明白JAVA常用的工具类
一篇文章讲明白JAVA常用的工具类
|
3天前
|
JSON Java 数据安全/隐私保护
一篇文章讲明白Java第三方支付接入案例(支付宝)
一篇文章讲明白Java第三方支付接入案例(支付宝)