Java中String字符串常量池总结
最近到广州某互联网公司面试,当时面试官问假设有两个字符串String a="abc",String b = "abc";问输出a==b是true还是false。我当时毫不犹豫答了true,然后根据字符串常量池的知识点结合jvm的内存模型讲解,然而他却跟我说是false,说这是最基本的问题。我当时一脸懵逼,跟他讨论了很长时间,后来发现他是错的,他说a,b两个变量是存在栈中,这两个引用是不一样的,只不过它们指向的内容是一样的。因为他毕竟工作了好几年,我当时也质疑我的知识点,所以当时也接受了他的答案。回来上机实践查资料求证之后,说明我是对的,具体内容整理如下。首先先上三份代码:
第一段:
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
String s3 = "he" + "llo";
String s4 = "hel" + new String("lo");
String s5 = new String("hello");
String s6 = s5.intern();
String s7 = "h";
String s8 = "ello";
String s9 = s7 + s8;
System.out.println(s1==s2);//true
System.out.println(s1==s3);//true
System.out.println(s1==s4);//false
System.out.println(s1==s9);//false
System.out.println(s4==s5);//false
System.out.println(s1==s6);//true
}
在jdk1.6,1.7,1.8下运行的结果为:
System.out.println(s1==s2);//true
System.out.println(s1==s3);//true
System.out.println(s1==s4);//false
System.out.println(s1==s9);//false
System.out.println(s4==s5);//false
System.out.println(s1==s6);//true
第二段:
public static void main(String[] args) {
String s1 = new String("hello");
String intern1 = s1.intern();
String s2 = "hello";
System.out.println(s1 == s2);
String s3 = new String("hello") + new String("hello");
String intern3 = s3.intern();
String s4 = "hellohello";
System.out.println(s3 == s4);
}
在jdk1.6下运行的结果为:
false,false
在jdk1.7,1.8下运行的结果为:
false,true
第三段:
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = "hello";
String intern1 = s1.intern();
System.out.println(s1 == s2);
String s3 = new String("hello") + new String("hello");
String s4 = "hellohello";
String intern3 = s3.intern();
System.out.println(s3 == s4);
}
在jdk1.6下运行的结果为:
false,false
在jdk1.7,1.8下运行的结果为:
false,false
第一段代码:
String类的final修饰的,以字面量的形式创建String变量时,jvm会在编译期间就把该字面量(“hello”)放到字符串常量池中,由Java程序启动的时候就已经加载到内存中了。这个字符串常量池的特点就是有且只有一份相同的字面量,如果有其它相同的字面量,jvm则返回这个字面量的引用,如果没有相同的字面量,则在字符串常量池创建这个字面量并返回它的引用。由于s2指向的字面量“hello”在常量池中已经存在了(s1先于s2),于是jvm就返回这个字面量绑定的引用,所以s1==s2。s3中字面量的拼接其实就是“hello”,jvm在编译期间就已经对它进行优化,所以s1和s3也是相等的。s4中的new String("lo")生成了两个对象,"lo","new String("lo")","lo"存在字符串常量池,"new String("lo")"存在堆中,String s4 = "hel" + new String("lo")实质上是两个对象的相加,编译器不会进行优化,相加的结果存在堆中,而s1存在字符串常量池中,当然不相等。s1==s9的原理一样。s4==s5两个相加的结果都在堆中,不用说,肯定不相等。s1==s6中,s5.intern()方法能使一个位于堆中的字符串在运行期间动态地加入到字符串常量池中(字符串常量池的内容是程序启动的时候就已经加载好了),如果字符串常量池中有该对象对应的字面量,则返回该字面量在字符串常量池中的引用,否则,创建复制一份该字面量到字符串常量池并返回它的引用。因此s1==s6输出true。
第二段代码:
jdk1.6下字符串常量池是在永久区中,是与堆完全独立的两个空间,s1指向堆中的内容,s2指向字符串常量池中的内容,两者当然不一样,s1.intern1()将字面量加入字符串常量池中,由于字符串常量池中已经存在该字面量,所以返回该字面量的唯一引用,intern1==s2就输出true。
jdk1.7,1.8下字符串常量池已经转移到堆中了,是堆中的一部分内容,jvm设计人员对intern()进行了一些修改,当执行s3.intern()时,jvm不再把s3对应的字面量复制一份到字符串常量池中,而是在字符串常量池中存储一份s3的引用,这个引用指向堆中的字面量,当运行到String s4 = "hellohello"时,发现字符串常量池已经存在一个指向堆中该字面量的引用,则返回这个引用,而这个引用就是s3。所以s3==s4输出true。
第三段代码:
jdk1.6下输出false,false,原理和上面一样。
jdk1.7,1.8下输出false,false,s3指向堆内容,接着s4="hellohello"发现字符串常量池中没有该字面量,创建并返回该引用。s3,s4一个在堆,一个在字符串常量池,是两个独立的引用,所以s3==s4输出false。
2018-03-17 05:44:23
Java中String字符串常量池总结的更多相关文章
- Java中String字符串常量池
首先看一个例子,通过这个例子更能快速理解String常量池 public static void main(String[] args) { String a = "ab"; St ...
- 转载:Java中的字符串常量池详细介绍
引用自:http://blog.csdn.net/langhong8/article/details/50938041 这篇文章主要介绍了Java中的字符串常量池详细介绍,JVM为了减少字符串对象的重 ...
- Java中的字符串常量池,栈和堆的概念
问题:String str = new String(“abc”),“abc”在内存中是怎么分配的? 答案是:堆内存.(Tips:jdk1.8 已经将字符串常量池放在堆内存区) 题目考查的为Ja ...
- Java中的字符串常量池
ava中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";,另一种就是使用new这种标准的构造对象的方法,如String str = new ...
- Java中的字符串常量池和JVM运行时数据区的相关概念
什么是字符串常量池 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量 ...
- Java进阶——Java中的字符串常量池
转载. https://blog.csdn.net/qq_30379689/article/details/80518283 字符串常量池 JVM为了减少字符串对象的重复创建,其内部维护了一个特殊的内 ...
- Java中的字符串常量池?
参考:http://droidyue.com/blog/2014/12/21/string-literal-pool-in-java/index.html
- string字符串常量池在内存中的位置
这里仅仅是举个简单的样例说明字符串常量池在内存中的位置. 闲言少叙,直接上代码. <span style="font-size: large;">import java ...
- java中String字符串的==解析
今天不知道怎么看了下string的==的问题,本身我觉得我这个水平去判断几个字符串相等还能出问题?呵呵,真的出了大问题,根本原因在于对java字节码的不了解. 首先,==运算符比较的是两个变量所指向的 ...
随机推荐
- 基于jquery的城市选择插件
城市选择插件的难度不是很大,主要是对dom节点的操作.而我写的这个插件相对功能比较简答,没有加入省市联动. 上代码好了,参照代码的注释应该比较好理解. /* *基于jquery的城市选择插件 *aut ...
- 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题
layout: post title: 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题 key: 20180303 tags: GIT 版本管理 modify_date: 2 ...
- UESTC 251 最长上升子序列O(nlgn)
O(n^2)过不了.必须要用一个额外的数组保存当前长度最小值,然后lgn查表 AC代码 #include<cstdio> #include<algorithm> using n ...
- 【2016北京集训测试赛(十六)】 River (最大流)
Description Special Judge Hint 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. 题解 题目大意:给定两组点,每组有$n$个点,有若干条跨组 ...
- mac上搭建appium+IOS自动化测试环境(一)
阅读须知 由于OS X系统最近才开始接触,所以有些东西也不是很清楚,这里只提供方法不提供原理,能解释清楚的我也会尽量解释.可能也有一些地方说的不严谨或有错的,还望大家指点一二. 实验环境 操作系统: ...
- 项目实战14—ELK 企业内部日志分析系统
一.els.elk 的介绍 1.els,elk els:ElasticSearch,Logstash,Kibana,Beats elk:ElasticSearch,Logstash,Kibana ① ...
- jmeter 脚本规范
总结了一下公司正在用 jmeter 脚本规范. 使用 jmeter 进行接口级测试, 随着接口增多以及业务逻辑越来越复杂, 导致 jmeter 脚本的维护会更加困难.针对实际使用中发现的问题进行一些规 ...
- css在盒子中垂直居中和固定居中
顶部固定居中 <div class="w960 fixed"> 我是固定的 </div> .w960{ width: 960px; margin:0 aut ...
- Linux查看内存使用量和交换区使用量
Linux查看内存使用量和交换区使用量 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ free -m total used free shared buffe ...
- Django学习-19-缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5 ...