网站首页 > java教程 正文
下面的代码运行结果是什么?解释一下为什么会有这些差异。
String s1 = "hello";
String s2 = s1 + ",world";
String s3 = "hello" + ",world";
String s4 = "hello,world";
String s5 = new String("hello,world");
System.out.println(s2.equals(s4)); // true
System.out.println(s2==s4); // false
System.out.println(s3==s4); // true
System.out.println(s4==s5); // false
看似简单的代码,却有很多学问在里面。在此之前先非常简单地说一下JVM中的栈和堆,栈一般存放的是局部变量,对象的引用等;堆一般放对象、常量等,在 jdk1.7 以后的版本,字符串常量池也在堆中。
字符串常量池
一般情况下,创建字符串对象有两种方式,一种是字面值创建,一种是 new 创建,这两者是不一样的。
如果是字面值创建的方式,如 String s4="hello,world",JVM会先去字符串常量池中寻找有没有“hello,world”这个字符串,若有,则将其地址给 s4;若没有,则先在常量池里创建“hello,world”,然后再把地址给s4;而通过 new 的方式创建对象,则是在堆中创建“hello,world”对象,s5 指向这个对象。还是看图吧,比较直观:
equals() 和 ==
这是 Java 面试常考点,有人可能会说 equals() 比较的是值,而 == 比较的是对象的引用(没错是我),直到被面试官吊打,才会老老实实去看 Object 类中 equals() 的源码:
可以看到,equals() 方法体中,返回的是 两个对象的引用的比较结果 。但是,两个 String 类型 == 和 equals() 有时候结果却不一样。那是因为在 String 类中,equals() 被重写了:
可以看到,它先对比两个引用;若一样则直接返回 true,不一样就对它们的值进行比较。因此,可以对 == 和 equals() 更好的区别了:
字符串的拼接
String 类被 final 修饰,因此字符串不能修改,当两个字符串相加时,是先生成 StringBuilder 对象,然后通过 append() 的方式将两个字符串拼接,再调用 toString() 方法生成新的字符串对象。所以只考虑 s1 和 s2,他们在 JVM 中是这样的:
但是像 String s3 = "hello" + ",world" 这样直接两个字面值相加的,java文件在编译期间就已经将这条语句做了优化,将其直接变成 "hello,world",等到运行的时候就查找字符串常量池,因此 s3 == s4 返回的结果就为 true。
String、StringBuilder、StringBuffer
既然上面说到了 StringBuilder,那就顺便简单说一下这三者之间的区别。
String 是常量,且每次需要在原来字符串基础上扩展都需要新建对象,导致速度会稍微慢一点,而且占内存,因此对于需要经常扩展的字符串,可以使用 StringBuilder 和 StringBuffer。但是 StringBuilder 和 StringBuffer 又有区别,即时两者很像,在速度上 StringBuilder 会快一些,因为 StringBuffer 的操作加了 synchronized ,即加了锁,使得操作相对比较慢,就举 append() 为例子,StringBuffer 中此方法的源码如下:
所以,一般在单线程的情况下,可以选择使用 StringBuilder;在多线程的情况下可以选择 StringBuffer .
总结
回到一开始的程序,我们可以大致地画出在 JVM 中的存储:
猜你喜欢
- 2024-10-18 java面试题之三:字符串操作(字符串笔试题java)
- 2024-10-18 Jmeter BeanShell循环:字符串 拼接模式,为变量名 获取数据值
- 2024-10-18 连接字符串除了“+”还有哪些方法,进来看
- 2024-10-18 初识java—(三十四)String、StringBuffer和StringBuilder类
- 2024-10-18 初学者都在坑里!不要在Python中使用“+”来连接字符串
- 2024-10-18 Java中字符串连接运算符“+”的困惑
- 2024-10-18 Guava之字符串连接,分割,匹配处理
- 2024-10-18 【老梁聊IT之JAVA篇】StringBuilder的正确使用方法详解
- 2024-10-18 为何Java8中不再需要StringBuilder拼接字符串
- 2024-10-18 为什么阿里巴巴不建议在循环体中使用+进行字符串拼接?
你 发表评论:
欢迎- 最近发表
-
- Java常量定义防暴指南:从"杀马特"到"高富帅"的华丽转身
- Java接口设计原则与实践:优雅编程的艺术
- java 包管理、访问修饰符、static/final关键字
- Java工程师的代码规范与最佳实践:优雅代码的艺术
- 编写一个java程序(编写一个Java程序计算并输出1到n的阶乘)
- Mycat的搭建以及配置与启动(mycat部署)
- Weblogic 安装 -“不是有效的 JDK Java 主目录”解决办法
- SpringBoot打包部署解析:jar包的生成和结构
- 《Servlet》第05节:创建第一个Servlet程序(HelloSevlet)
- 你认为最简单的单例模式,东西还挺多
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)