最近到广州某互联网公司面试,当时面试官问假设有两个字符串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字符串常量池总结的更多相关文章

  1. Java中String字符串常量池

    首先看一个例子,通过这个例子更能快速理解String常量池 public static void main(String[] args) { String a = "ab"; St ...

  2. 转载:Java中的字符串常量池详细介绍

    引用自:http://blog.csdn.net/langhong8/article/details/50938041 这篇文章主要介绍了Java中的字符串常量池详细介绍,JVM为了减少字符串对象的重 ...

  3. Java中的字符串常量池,栈和堆的概念

    问题:String str = new String(“abc”),“abc”在内存中是怎么分配的?    答案是:堆内存.(Tips:jdk1.8 已经将字符串常量池放在堆内存区) 题目考查的为Ja ...

  4. Java中的字符串常量池

    ava中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";,另一种就是使用new这种标准的构造对象的方法,如String str = new ...

  5. Java中的字符串常量池和JVM运行时数据区的相关概念

    什么是字符串常量池 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量 ...

  6. Java进阶——Java中的字符串常量池

    转载. https://blog.csdn.net/qq_30379689/article/details/80518283 字符串常量池 JVM为了减少字符串对象的重复创建,其内部维护了一个特殊的内 ...

  7. Java中的字符串常量池?

    参考:http://droidyue.com/blog/2014/12/21/string-literal-pool-in-java/index.html

  8. string字符串常量池在内存中的位置

    这里仅仅是举个简单的样例说明字符串常量池在内存中的位置. 闲言少叙,直接上代码. <span style="font-size: large;">import java ...

  9. java中String字符串的==解析

    今天不知道怎么看了下string的==的问题,本身我觉得我这个水平去判断几个字符串相等还能出问题?呵呵,真的出了大问题,根本原因在于对java字节码的不了解. 首先,==运算符比较的是两个变量所指向的 ...

随机推荐

  1. Netbeans简要配置许可证信息

    <#if licenseFirst??>${licenseFirst}</#if>${licensePrefix}Copyright (C) <2017>  < ...

  2. PHP页面间的参数传递

    我们定义page01.php和page02.php两个php文件,将page01中的内容想办法传递到page02,然后供我们继续使用.--------------------------------- ...

  3. Samba服务器的安装与配置

    Samba服务器主要的功能是实现本地windows系统下方便读写局域网内虚拟机下的文件: Samba与window连接需要使用NetBIOS协议,请确认你的Windows系统已经安装了NetBIOS协 ...

  4. 最简化搭建yum仓库

    在使用rpm安装软件包时,时常会遇到一些软件依赖性问题,如果是简单的一两个依赖性还是可以手动解决.要是出现大量的依赖性问题的话会让增大工作量.yum是一个很好的前端程序,可解决软件包相关依赖性,可在多 ...

  5. 转: JavaScript 获取对象属性和方法

    一.获取对象属性和方法 Object.keys()for in 返回对象的可枚举属性和方法的名称数组. Object.getOwnPropertyNames() 返回的数组的所有属性(可枚举或不可枚举 ...

  6. shell脚本 字串截取 正则表达式

    字串处理 子串截取方法一:使用${}表达式格式:echo ${x:起始位置:长度}(起始位置编号从0开始,可省略) 方法二:使用expr substr格式:expr substr "$x&q ...

  7. Linux内核开发之将驱动程序添加到内核

    驱动程序添加到内核 一.概述: 在Linux内核中增加程序需要完成以下三项工作: 1.将编写的源代码复制到Linux内核源代码的相应目录 2.在目录的Kconfig文件中增加新源代码对应项目的编译配置 ...

  8. Linux查看非root运行的进程

    Linux查看非root运行的进程 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ ps -U root -u root -N PID TTY TIME CMD ...

  9. SQL错误:ORA-12899

    1.错误描述 SQL错误:ORA-12899:列"USER"."T_USER_TAB"."USER_ID"的值太大(实际值:4,最大值:2) ...

  10. “玲珑杯”ACM比赛 Round #4 B Best couple

    一眼的KM,但是建图的时候记得不用的点设为0,点少的一边补齐,这个非常重要,因为KM追求完全匹配,如果无法完全匹配会非常慢 #include<bits/stdc++.h> using na ...