最近到广州某互联网公司面试,当时面试官问假设有两个字符串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. PHP常见面试题总结

    1.include 和 require 都能把另外一个文件包含到当前文件中 他们有什么区别?include 和 include_once 又有什么区别? 二者区别只有一个,那就是对包含文件的需求程度 ...

  2. 试着把.net的GC讲清楚(3)

    前两篇写的都是gc的一些概念和细节,这些东西对自己以后写代码有什么用,本篇我就准备将这些内容. root 第一篇文章中讲了GC在遍历存活对象的时候,都是从root开始的,root是一些对象的引用,例如 ...

  3. kubernetes 命令使用

    学会命令的查找和使用,而不是死记命令,记命令不如提高英文水平 1.kubernetes环境搭建完成后,kubernetes环境搭建参考http://www.cnblogs.com/sosogengdo ...

  4. AppCompatActivity 去掉标题栏和EditText弹出软键盘遮住输入框问题

    1. AppCompatActivity去掉标题栏 此处除掉标题栏,需要注意一点,AppCompactActivity是继承自Activity.然而,AppCompactActivity据查看网上资料 ...

  5. Hive语法

    1.Select 语法 SELECT [ALL | DISTINCT] select_expr, select_expr, ... FROM table_reference [WHERE where_ ...

  6. APICloud常用模块

    常用模块 基础 fs db 支付 wxPay aliPay unionPay 消息 ajpush rongCloud2

  7. Jmeter MD5插件

    实际业务中,会要求 HTTP 协议中附加 MD5 校验字段, 防止请求参数被恶意篡改, 对于开发同学来说, 这是个很简单的需求. 但是给自动化测试增加了难度, Jmeter 原生不支持这个功能,应测试 ...

  8. jquery 图片转为base64

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  9. jvm类加载器和双亲委派模型

    类加载器按照层次,从顶层到底层,分为以下三种:  (1)启动类加载器(Bootstrap ClassLoader)   这个类加载器负责将存放在JAVA_HOME/lib下的,或者被-Xbootcla ...

  10. php 递归无线级别分类

    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <?ph ...