相同字符串,但是equals为false?我多年的java白学了吗?

沙海 2021年4月2日11:27:39杂谈 Java评论89字数 3094阅读10分18秒阅读模式
摘要

速读摘要

速读摘要文章源自JAVA秀-https://www.javaxiu.com/8227.html

看一下就知道了,或者直接按F12审查元素也可以看到。这下应该很清楚的知道了为什么两个字符串toString()看起来一样,但是equals却为false。说一个最常见的场景,window下新建一个test.txt文件(用window自带的记事本),随便写点什么,就"helloworld"吧。文章源自JAVA秀-https://www.javaxiu.com/8227.html

原文约 1948 | 图片 7 | 建议阅读 4 分钟 | 评价反馈文章源自JAVA秀-https://www.javaxiu.com/8227.html

相同字符串,但是equals为false?我多年的java白学了吗?

程序员闪充宝 文章源自JAVA秀-https://www.javaxiu.com/8227.html

相同字符串,但是equals为false?我多年的java白学了吗?文章源自JAVA秀-https://www.javaxiu.com/8227.html

作者:Sicimike文章源自JAVA秀-https://www.javaxiu.com/8227.html

blog.csdn.net/Baisitao_/article/details/92667122文章源自JAVA秀-https://www.javaxiu.com/8227.html

前言

有时候写代码会遇到一些莫名其妙的问题,两个字符串明明toString()打印一模一样,但是equals就是为false。文章源自JAVA秀-https://www.javaxiu.com/8227.html

问题

直接看代码文章源自JAVA秀-https://www.javaxiu.com/8227.html

public static void main(String[] args) {   String s1 = "hello‌world‌";   String s2 = "helloworld";   System.out.println(s1.equals(s2));}

这代码应该够简单了,毫无疑问输出true啊。但是我们还是实际操作一下:文章源自JAVA秀-https://www.javaxiu.com/8227.html

相同字符串,但是equals为false?我多年的java白学了吗?文章源自JAVA秀-https://www.javaxiu.com/8227.html

这是什么情况,居然输出了false,我多年的java白学了吗?文章源自JAVA秀-https://www.javaxiu.com/8227.html

结论

其实这个问题很简单,因为字符串s1中包含了不可打印字符,可以把两个字符串复制到 QQ/TIM 看一下就知道了,或者直接按F12审查元素也可以看到。或者我们继续在Java代码中查看文章源自JAVA秀-https://www.javaxiu.com/8227.html

public static void main(String[] args) {    String s1 = "hello‌world‌";    String s2 = "helloworld";    System.out.println(s1.equals(s2));    System.out.println(Arrays.toString(s1.getBytes()));    System.out.println(Arrays.toString(s2.getBytes()));}

相同字符串,但是equals为false?我多年的java白学了吗?文章源自JAVA秀-https://www.javaxiu.com/8227.html

这下应该很清楚的知道了为什么两个字符串toString()看起来一样,但是equals却为false。文章源自JAVA秀-https://www.javaxiu.com/8227.html

不可见字符从哪来

说一个最常见的场景,window下新建一个test.txt文件(用window自带的记事本),随便写点什么,就“helloworld”吧。保存(另存为)的时候选择UTF-8编码。文章源自JAVA秀-https://www.javaxiu.com/8227.html

相同字符串,但是equals为false?我多年的java白学了吗?文章源自JAVA秀-https://www.javaxiu.com/8227.html

这种方式保存的文件,window会在文件头部添加一个字符,叫做BOM(byte-order mark,字节顺序标记)以UTF-8编码时是三个字节,分别是EF BB BF,用来标记这是一个UTF8编码的文件。程序读取文件时,会把BOM头一起读入内存:文章源自JAVA秀-https://www.javaxiu.com/8227.html

public static void compareContent() {        InputStream is = null;        try {            is = new FileInputStream(new File("D:\\test.txt"));            byte[] buff = new byte[16];            int nRead = 0;            StringBuilder sb = new StringBuilder();            while ((nRead = is.read(buff)) != -1) {                sb.append(new String(buff, 0, nRead));            }            //UTF-8文件读取的字符串            String fileStr = sb.toString();            //程序定义的字符串,此处不包含不可打印字符            String localStr = "helloworld";            System.out.println(fileStr.toString());            System.out.println(localStr.toString());            System.out.println("文件字符串:" + Arrays.toString(fileStr.getBytes()));            System.out.println("本地字符串:" + Arrays.toString(localStr.getBytes()));        } catch (IOException e) {            e.printStackTrace();        } finally {            if (is != null) {                try {                    is.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }

运行结果如下:文章源自JAVA秀-https://www.javaxiu.com/8227.html

相同字符串,但是equals为false?我多年的java白学了吗?文章源自JAVA秀-https://www.javaxiu.com/8227.html

除了前三个字节,后面的内容其实是一模一样的。文章源自JAVA秀-https://www.javaxiu.com/8227.html

解决办法

如果文件非要以UTF-8编码保存,可以有以下几种方法:文章源自JAVA秀-https://www.javaxiu.com/8227.html

  • 保存的时候去掉BOM头(notepad++支持以UTF-8无BOM格式编码文章源自JAVA秀-https://www.javaxiu.com/8227.html

  • 程序做兼容,兼容代码如下:文章源自JAVA秀-https://www.javaxiu.com/8227.html

public static String deleteUTF8Bom(String fileStr) {    byte[] UTF8_BOM_BYTES = new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};    byte[] bytes = fileStr.getBytes();    if (bytes[0] == UTF8_BOM_BYTES[0]             && bytes[1] == UTF8_BOM_BYTES[1]             && bytes[2] == UTF8_BOM_BYTES[2]) {         return new String(bytes, 3, bytes.length - 3);     }    return fileStr;}

总结

这个问题不太容易发现,但是其实也是属于基础内容。也说明眼见不一定为实,看到的字符串不一定就是真正的字符串。文章源自JAVA秀-https://www.javaxiu.com/8227.html

@Autowire和@Resource注解使用的正确姿势,这些年我一直用错了!!华为面试官:为什么 HashMap 的加载因子是0.75?强大:MyBatis 流式查询华为面试官:为什么 HashMap 的加载因子是0.75?SpringBoot+OAuth2+JWT实现单点登录SSO完整教程,竟如此简单优雅!趣头条面试题:ThreadLocal是什么?怎么用?为什么用它?有什么缺点Springboot启动扩展点超详细总结,再也不怕面试官问了趣头条面试题:ThreadLocal是什么?怎么用?为什么用它?有什么缺点List去除重复数据的五种方式,学到了...SpringBoot操作ES进行各种高级查询(必须收藏)点击阅读全文前往微服务电商教程
文章源自JAVA秀-https://www.javaxiu.com/8227.html
继续阅读
速蛙云 - 极致体验,强烈推荐!!!购买套餐就免费送各大视频网站会员!快速稳定、独家福利社、流媒体稳定解锁!速度快,全球上网、视频、游戏加速、独立IP均支持!基础套餐性价比很高!这里不多说,我一直正在使用,推荐购买:https://www.javaxiu.com/59919.html
weinxin
资源分享QQ群
本站是JAVA秀团队的技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
沙海
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定