【JavaSE】你可能不知道的equals方法与==细节问题

👽 博客主页: <芝士盘盘>
❤️‍🔥💗💓一键三连:👍 点赞 ✌️ 收藏 👌 关注
👻小小勉励:穷且益坚,不坠青云志


前言
在学习过程中,我们常常会忽略一些细节问题,这些问题往往隐藏在简单的语法下,很容易让人不去关注,但这些问题是切实存在的,不在意往往会导致编程中容易出现错误,想要成为优秀的程序员,我们应当多去深究这些看似影响不大的细枝末节。



一、"=="

“==”是一个运算符,其实大家很熟悉,在学习一开始学习C语言的时候就早已经遇到过,它最基本的作用肯定都知道,就是判断等号左右两边是否相等对吧。但是,在Java中,由于加入了对象🔍的概念,并且将数据类型分为了基本数据类型🔍引用数据类型🔍,这就使得Java中使用它时候需要注意一些问题,接下来会进行讲解。


先说结论

“==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。

ok,既然“==”左边和右边可以是基本数据类型和引用数据类型,那无非就是四种情况咯,现在一一说明
注:接下来的基本数据类型将用int举例,引用数据类型将用Integer举例。


左右两边都为基本数据类型

public class Test {
    public static void main(String[] args) {
        int a = 1;
        int b = 1;
        int c = 2;
        System.out.println(a==b);
        System.out.println(a==c);
    }
}

输出结果:

true
false

这个不用多说,很显然。


左边为基本数据类型,右边为引用数据类型

public class Test {
    public static void main(String[] args) {
        int a = 1;
        Integer b = 1;
        Integer c = 2;
        System.out.println(a==b);
        System.out.println(a==c);
    }
}

输出结果:

true
false

这里有一个细节,就是在比较的时候会进行自动拆箱🔍的操作,Integer类型与int类型用==比较时会自动拆箱成int类型与之比较,这时Integer变成了int,那就和上面的情况一样了,输出结果自然是一样的。


左边为引用数据类型,右边为基本数据类型

public class Test {
    public static void main(String[] args) {
        Integer a = 1;
        int b = 1;
        int c = 2;
        System.out.println(a==b);
        System.out.println(a==c);
    }
}

输出结果:

true
false

这其实和上一种情况一样,只是左右顺序调换了而已。


左右两边都为引用数据类型

注意,这种情况是我们需要重点探讨的

public class Test {
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        Integer c = 200;
        Integer d = 200;
        System.out.println(a==b);
        System.out.println(c==d);
    }
}

输出结果:

true
false

诶?这时候小伙伴们就要问了,为啥呀,200和200难道不相等嘛?

其实原因很简单,前面说了,如果==比较的是引用数据类型,比较的是它们的地址,Integer本质上是一个类,我们给Integer赋值时,系统会进行一个操作,自动装箱🔍,也就是说将等号右边的int变成了Integer,这里调用了valueOf方法。

public class Test {
    public static void main(String[] args) {
        //Integer a = 100;
        //Integer b = 100;
        //Integer c = 200;
        //Integer d = 200;
        Integer a = Integer.valueOf(100);
        Integer b = Integer.valueOf(100);
        Integer c = Integer.valueOf(200);
        Integer d = Integer.valueOf(200);
        System.out.println(a==b);
        System.out.println(c==d);
    }
}

很显然,会导致问题出现的原因在于valueOf方法上,我们来看看valueOf的源码。

 public static Integer valueOf(int i) {
        if (i >= -128 && i <= 127)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
}

可以发现,当i >= -128 && i <= 127时,会返回一个缓存中已有的Integer对象,当i不在这个范围时,会返回一个新的对象。
噢!!这时候我们就可以明白了,我们赋值100的时候,属于-128到127的范围内,返回的引用都是同一个对象,那么同一个对象的地址当然是一样的咯。当赋值200的时候,不在范围内,返回的是一个新的对象,所以地址当然不一样,结果就是false。


二、“equals()”

equals是Object的方法,用来比较两个对象的内容是否相等。

方法源码:

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

很明显,我们可以看出这个方法还是比较2个对象引用地址是否相同,但是我们平时在调用String、Integer等封装类型时的equals方法时是比较的内容是否一致而不是地址一致,为此引用数据类型都重写🔍了equals方法。

下面,以String类型为例,我们来看看它的源码。

public boolean equals(Object anObject) {  
    //这里比较的是地址
    if (this == anObject) {  
        return true;  
    }  
    //判断是否为String对象
    if (anObject instanceof String) {  
    //是String对象进行强转
        String anotherString = (String)anObject; 
        int n = value.length;  
    //判断两个string长度是否一样,一样的话进入循环
        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;  
}

根据以上源码可以看出封装类型的String对equals进行了重写,其他封装类型原理一样,只是根据不同的类型去判断值,所以如果还像上面比较200的时候就不会出现返回false的问题啦。


三、为何自定义类要重写“equals()”?

我们现在明白了引用类型都重写了Object类中的equals方法,这才使得我们在比较这些类型的时候比较的是他们的值而不是地址。那么,我们在自定义类的时候自然也要重写equals,因为所有类都是Object的子类,只有重写了equals才能实现比较的是值而不是地址的功能。


写在最后
完整的看完整篇博客,是不是觉得原来这里面还有这些门门道道呢,其实还有很多细节都值得我们去关注,只有在细节上钻研的越多,才能在写代码的时候犯的错误越少哦。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值