在逛 Stack Overflow 的时候,发现了一些访问量像喜马拉雅山一样高的问题,比如说这个:如何比较 Java 的字符串?访问量足足有 370万+,这不得了啊!说明有很多很多的程序员被这个问题困扰过。

PS:之前写过一篇《Stack Overflow 上 250万 浏览量的一个问题:你对象丢了》,阅读量还不错,这给了我极大的信心继续把这个系列写下去。

我们来回顾一下提问者的问题:

截止到目前为止,我一直使用“==”操作符来比较字符串,直到程序出现了一个 bug,需要使用 .equals() 方法来解决。这是为什么呢?“==”操作符和 .equals() 方法之间有什么区别呢?

和提问者相反,在我刚开始学习 Java 的时候,比较字符串一直使用的是 .equals() 方法,因为不管是书本还是老师,都告诫我不要直接使用“==”操作符来比较,会出 bug。至于为什么,书本和老师都没有帮我搞清楚。

那借此机会,我就来梳理一下 Stack Overflow 上的高赞答案,我们来一起学习进步,打怪升级。

  • “==”操作符用于比较两个引用(内存中的存放地址)是否相等,它们是否是同一个对象。
  • .equals() 用于比较两个对象的内容是否相等。

怎么理解这两句话呢?我来举个不恰当又很恰当的例子。

有一对双胞胎,姐姐叫阿丽塔,妹妹叫洛丽塔。我们普通人的眼睛完全无法分辨谁是姐姐谁是妹妹,可她们的妈妈却可以轻而易举地辨认出。

.equals() 就好像我们普通人,看见阿丽塔以为是洛丽塔,看见洛丽塔以为是阿丽塔,看起来一样就觉得她们是同一个人;“==”操作符就好像她们的妈妈,要求更严格,观察更细致,一眼就能分辨出谁是姐姐谁是妹妹。


String alita = new String("小萝莉");
String luolita = new String("小萝莉");System.out.println(alita.equals(luolita)); // true
System.out.println(alita == luolita); // false

就上面这段代码来说,.equals() 输出的结果为 true,而“==”操作符输出的结果为 false——前者没后者要求那么严格。

大家都知道,Java 的所有类都默认地继承着 Object 这个超类,该类有一个名为 .equals() 的方法,源码如下所示。


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

可以看得出,Object 类的 .equals() 方法默认采用的是“==”操作符进行比较。假如子类没有重写该方法的话,那么“==”操作符和 .equals() 方法的功效就完全一样——比较两个对象的内存地址或者对象的引用是否相等。

但实际情况中,有不少类重写了 .equals() 方法,因为比较内存地址太重了,不太符合现实的场景需求。String 类就重写了 .equals() 方法,源码如下所示。


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;
}

可以看得出,如果两个字符串对象“==”,那么 .equals() 的结果就为 true;否则的话,就比较两个字符串的内容是否相等。

大家应该都知道了,创建字符串对象有两种写法,如下所示。


String luolita = "小萝莉";
String alita = new String("小萝莉");

第一种是在字符串常量池(存储在方法区)中创建对象,并将对象的引用赋值给 luolita。第二种是通过 new 关键字在堆中创建对象,并将对象引用赋值给 alita。

PS:字符串作为最基础的数据类型,使用非常频繁,如果每次都通过 new 关键字进行创建,会耗费高昂的时间和空间代价。Java 虚拟机为了提高性能和减少内存开销,就设计了字符串常量池:相同字面量的对象只有一个。

PPS:Java 虚拟机在执行程序的过程中会把内存区域划分为若干个不同的数据区域,如下图所示。

下面我们通过实际代码来看看字符串的比较。

第一种:


new String("小萝莉").equals("小萝莉") // --> true 

.equals() 比较的是两个字符串对象的内容是否相等,所以结果为 true。

第二种:


new String("小萝莉") == "小萝莉" // --> false 

“==”操作符左侧的对象存储在堆中,右侧的对象存储在方法区,所以返回 false。

第三种:


new String("小萝莉") == new String("小萝莉") // --> false 

new 出来的两个对象肯定是不相等的,所以返回 false。

第四种:


"小萝莉" == "小萝莉" // --> true 

字符串常量池中只会有一个对象,所以返回 true。

"小萝莉" == "小" + "萝莉" // --> true

由于“小”和“萝莉”都在字符创常量池,所以编译器会将其自动优化为“小萝莉”,所以返回 true。

经过大量实例的分析,我们可以得出如下结论(也是对提问者的回答):

  • 当比较两个字符串对象的内容是否相等时,请使用 .equals() 方法。
  • 当比较两个字符串对象是否相等时,请使用“==”操作符。

当然了,如果要进行两个字符串对象的内容比较,除了 .equals() 方法,还有其他可选的方法。

1)Objects.equals()

Objects.equals() 这个静态方法的优势在于不需要在调用之前判空。


public static boolean equals(Object a, Object b) {return (a == b) || (a != null && a.equals(b));
}

如果直接使用 a.equals(b),则需要在调用之前对 a 进行判空,否则可能会抛出空指针 java.lang.NullPointerException


Objects.equals("小萝莉", new String("小" + "萝莉")) // --> true
Objects.equals(null, new String("小" + "萝莉")); // --> false
Objects.equals(null, null) // --> trueString a = null;
a.equals(new String("小" + "萝莉")); // throw exception

2)String 类的 .contentEquals()

.contentEquals() 的优势在于可以将字符串与任何的字符序列(StringBuffer、StringBuilder、String、CharSequence)进行比较。


public boolean contentEquals(CharSequence cs) {// Argument is a StringBuffer, StringBuilderif (cs instanceof AbstractStringBuilder) {if (cs instanceof StringBuffer) {synchronized(cs) {return nonSyncContentEquals((AbstractStringBuilder)cs);}} else {return nonSyncContentEquals((AbstractStringBuilder)cs);}}// Argument is a Stringif (cs instanceof String) {return equals(cs);}// Argument is a generic CharSequencechar v1[] = value;int n = v1.length;if (n != cs.length()) {return false;}for (int i = 0; i < n; i++) {if (v1[i] != cs.charAt(i)) {return false;}}return true;
}

从源码上可以看得出,如果 cs 是 StringBuffer,该方法还会进行同步,非常的智能化。不过需要注意的是,使用该方法之前,需要确保比较的两个字符串都不为 null,否则将会抛出空指针。

再强调一点,.equals() 方法在比较的时候需要判 null,而“==”操作符则不需要。


System.out.println( null == null); // --> true

转载:https://mp.weixin.qq.com/s?__biz=MzIxNzQwNjM3NA==&mid=2247486394&idx=1&sn=f069dc6c6d3e89be22888fde3392fc2b&scene=21#wechat_redirect

如何比较 Java 的字符串相关推荐

  1. java从字符串中提取数字

    1.做一下操作时会一般会用到提取数字操纵: a.列表中有翻页,当新添加的数据不是放在第一条或者最后一条时,需要翻页并循环找到对应的那条数据 b.当新添加的数据放在第一条或者最后一条时,则不需要翻页,只 ...

  2. 判断字符串不包含某个字符php,java判断字符串是否包含某个字符的方法

    java判断字符串是否包含某个字符的方法: 一.contains方法 1:描述 java.lang.String.contains() 方法返回true,当且仅当此字符串包含指定的char值序列 2: ...

  3. java案例——字符串反转

    java案例--字符串反转 1.需求: 定义一个方法,实现字符串反转.键盘录入一个字符串,调用该方法后,在控制台输出结果 例如,键盘录入abc,输出结果cba 2.思路: 1.键盘录入一个字符串,用S ...

  4. Java案例——字符串拼接

    Java案例--字符串拼接案例 1.案例需求 定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果 例如,数字为int[] arr = {1,2,3}; ...

  5. java之字符串学习记录

    java之字符串学习记录 public class StringDemo { public static void main(String[] args) { //静态初始化字符串 String s1 ...

  6. JAVA关于字符串字符数组处理的小题目

    JAVA关于字符串&&字符数组的小题目 第二题:分析以下需求,并用代码实现 1.键盘录入一个大字符串,再录入一个小字符串 2.统计小字符串在大字符串中出现的次数 3.代码运行打印格式: ...

  7. Java:字符串类String的功能介绍

    在java中,字符串是一个比较常用的类,因为代码中基本上处理的很多数据都是字符串类型的,因此,掌握字符串类的具体用法显得很重要了. 它的主要功能有如下几种:获取.判断.转换.替换.切割.字串的获取.大 ...

  8. java 包含汉字,【转载】Java判断字符串中是不是包含汉字

    [转载]Java判断字符串中是否包含汉字 import java.util.regex.Matcher; import java.util.regex.Pattern; public class If ...

  9. jni和java之间字符串的转换

    jni和java之间字符串的转换方法. C的实现: JNIEXPORT jstring JNICALL Java_Android123_CwjC (JNIEnv *env, jobject obj, ...

  10. java 获取字符串长度_ava练习实例:java字符串长度与Java String charAt() 方法 (建议收藏)...

    JJava 字符串长度 public class StringDemo {public static void main(String args[]) {String palindrome = &qu ...

最新文章

  1. YII2框架表单-model(验证)-HTML_help部件 URL_help部件 以注册页面为实例
  2. React Native填坑之旅 -- 回归小插曲
  3. 矩形做成翻页的效果html5,HTML5 在canvas中绘制矩形附效果图
  4. sqldeveloper的查看执行计划快捷键F10
  5. Spring Boot笔记-mysql5.7使用@Table后提示doesn't exist问题
  6. 【转】桌面快捷方式不见了的解决办法
  7. Fiddler--QUICKEXER
  8. 黄河计算机学校,黄河(数学与计算机学院)老师 - 重庆三峡学院 - 院校大全
  9. 如何安装ipa文件(二)
  10. Linux操作系统资源 大合集【鸿蒙OS Suse 红帽 BSD CentOS Arch Ubuntu】 | 寻找C站宝藏
  11. flash 实例教程
  12. seekbar 的用法
  13. ant design vue折叠面板自定义header
  14. Mac 谷歌浏览器chrome恶意插件劫持Any search(TotalSearchToolbox)处理
  15. 微信小程序码获取-从频繁失败到成功率100%
  16. no-siteapp 和 no-transform 有什么区别??
  17. 漫谈程序员(十)大白菜装机版安装win7系统使用教程
  18. 手机视频如何投屏到电脑 手机投屏电脑
  19. 央行降息楼市应声而动:购房者出现恐慌苗头
  20. 更换内存条导致windows启动失败,报错信息:windows无法验证此文件的数字签名,2018.11;

热门文章

  1. c语言 rand_C语言随机数
  2. 软件工程师生存指南:面试准备、工作经验和实用工具
  3. oracle系统user$,Oracle 系统变量函数介绍
  4. 计算机复位启动如何操作,电脑能开机但进入不了系统,怎么办?按什么键能恢复系统?...
  5. android调用百度活体检测接口,C#调用百度API实现活体检测的方法
  6. mysql数据库表空间最大值_mysql 数据库取最大值
  7. mysql rpm conflict_解决centos7 yum安装MySQL rpm包出现conflict problem
  8. 重庆计算机二本专业有哪些专业,重庆高考计算机类分数线
  9. 使用计算机比喻的心理学研究取向,心理学入门:6个方面的研究取向
  10. java统计行列和字数的函数_JAVA使用POI获取Excel的列数与行数