简单了解Java中的 == 和 equals()


一、前情引入:

即使你刚学习编程语言,你肯定知道,=是赋值,==是判断是否相等,比如下面的程序:
在这里插入图片描述
可见,==判断了a和b是相等的,
如下图,内存中其实是这样存储a和b的,在栈中,经过比较两个10,是相等的。
在这里插入图片描述


二、对于数组:

接下来,让我们来看看==号用在数组中是什么情况:
在这里插入图片描述
可以看到,数组c和e为真,但c和d假,为什么呢?

在这里插入图片描述
原来,数组名是对数组的引用,数组实际上是存放在堆中的,栈中只存着堆首的地址,
在栈中,经过比较,c和e相等,但c和d不相等。


三、对于字符串:

再来看看今天最需要解决的问题——字符串:
在这里插入图片描述
结果是不是有点奇怪呢?怎么只有s1=s2,t1和t2不等吗?
这里先补充一下常量池的概念。
内存中除了堆和栈,还有一个区域叫方法区,
它一部分可以存放类的信息,还有一部分就是常量池了。

在这里插入图片描述
ps: 《堆、栈、方法区、常量池的概念》https://www.cnblogs.com/xiaowangbangzhu/p/10366200.html

如下图:
s1和s2都指向常量池的同一个地址,所以相等,
但t1和t2强行在堆中new了空间,所以不相等。

在这里插入图片描述


四、equals()方法:

在学习字符串中,你一定用到了equals()方法,它的作用是比较两个字符串内容是否相等,
还是上面的例子:
在这里插入图片描述

这回,s1=s2,并且t1=t2了,
所以,对于字符串,equals()就是判断两个字符串的值是否相等。

但实际上,equals()写在Object类中,和==作用是一样的,都是比较引用是否相等,
boolean b = obj1.equals(obj2);
只不过,字符串类将equals()进行了重写,才有了上图的结果。


五、本文总结:

1.java中的==和equals():

①如果是基本类型,如int、double,==比较的是值;
②如果是数组对象,==比较地址是否相等;
③字符串用equals()函数来比较是否相等。

ps:如果需要比较两个数组内容是否相等,也可以用equals()方法:
具体用法如下:
在这里插入图片描述
但是,还需要考虑到数组的顺序哦,所以,应该先排序后比较,如下图:
在这里插入图片描述


2.创建字符串的方法

①用new构造方法:

参考文档中给出了许多构造方法,比如用字符数组:

char[] chars= {'a','b','c','d','e'};
String s0=new String(chars);
//s0输出abcde

String s1=new String(new char[] {'a','b','c'});
//s1输出abcde
String s2=new String(chars,1,2);
//s2输出bc

或者用字符串:

String s3=new String("Hello World");
//s3输出Hello World

②也可以直接赋值,这叫做字符串常量:

String s4="hello";
//s4输出hello























上边,我们已经把常用到的情况做了区分,但有时候,我们也想根据自己的意愿改写equals()方法,
如果你想更深一步了解,请让我们一起接着往下:

P.S1. 改写equal()方法(原理)

请看下面的程序:这个程序new了两个对象,并用equals()方法比较。
在这里插入图片描述

前面我们已经知道,equals()方法在Object类中,
如果我们创建了一个类,就会自动继承了Object类,也就可以直接使用equals()方法了。

那这个程序的运行结果是什么呢?答案是False,因为new了不同的区域。

我们按住Alt,用鼠标点开equals()函数,查看源码如下。
在这里插入图片描述
可见,源码写的是——this当前对象(也就是a1)==传入的参数对象(也就是a2),
因为new了两个区域,所以应该返回False。

接下来,我们在A类中对equals()进行重写,如下:

在这里插入图片描述
可以看到,经过重写后,我们改变了equals()方法,于是对继承来的Object类中的equals()方法进行了覆盖,结果返回了True。

把上边的例子改写的正式一点:
在这里插入图片描述

P.S2. eclipse开发工具equals()自动生成(实用)

上面是从原理上分析,但并不实用,这一段落,我们将举一个生动的例子,并介绍实用的eclipse编译器自动生成equals()方法。

下图,创建一个Student类,有四个属性,添加上构造函数和get、set方法:

在这里插入图片描述
在另外一个类中的main方法中调用,得到False:
在这里插入图片描述

如果想让程序更加贴近生活,学号一样,就返回True,
即让对象有一个(或多个)标识,通过这个标识,
用生成equals()函数和hashCode方法(不用手写,直接用eclipse工具生成)。
步骤如下:
在这里插入图片描述

谁是标识你就选谁:

在这里插入图片描述
现在,编译器就自动为我们添加了hashCode()与equals(),
hashCode()方法我们可以注释掉,只用equals()方法,
现在再去比较,返回就是True了:
在这里插入图片描述


P.S3. 对于字符串的连接的==(拓展)(StringBuilder)

我们知道,字符串是可以通过 “+” 连接的,请看下面的一些案例:

案例1:

s1使用了字符串常量拼接,s2直接字符串常量赋值,内存地址是一样的。
在这里插入图片描述
ps:原理解释: jvm对

String s1="abc"+"def"+"asde";

进行了优化,实际上的编码就是

String s1="abcdefasde";

我们对上述的说法进行验证:
首先编译得到StringTest.class文件,
在这里插入图片描述
再使用javap -v 对生成的class文件进行反编译,可以看到下图红色方框的内容,
再结合前文常量池的概念,就可以得出结论——True了。
在这里插入图片描述

案例2:

在这里插入图片描述
相信你也有这样的疑问——用s3进行拼接为什么会出现false呢?

同样的,我们还是用刚才的方法:
在这里插入图片描述
得到.class文件后进行反编译:
在这里插入图片描述
内容太多,我就截取一部分:
在这里插入图片描述
可以看到,这里用到了StringBuilder,而且用到了它的append方法,
即:

String s9=s3+"world";

实际上的编码是:

String s9=new StringBuilder(s3).append("world");

这就意味着new了新的对象,有了新的地址空间,内存地址自然也就不同了。

PS:StringBuffer 类:
创建一个StringBuffer:

StringBuffer sBuffer1 = new StringBuffer();//空字符串
StringBuffer sBuffer = new StringBuffer("我爱");//有初值的字符串
   sBuffer.append("中国");
   sBuffer.append("!");
   System.out.println(sBuffer); //打印字符串

互相转化:

StringBuilder a  = new StringBuilder("I love you");
String b = ""+a;        //将StringBuilder类型转换成String类型
StringBuilder a  = new StringBuilder(a);        //将String类型转换为StringBuilder类型
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值