JAVA你真的了解String类型吗(String类型经典内存位置问题深入解读)
你真的了解String类型吗(String类型经典内存位置问题深入解读)
本文讲解一下String的基本情况,对于对应API方法不做涉及,本文所指JAVA环境为JAVA8
主要讲解内容:
public class StringTest {
public static void main(String[] args) {
String hello = "Hello";
String world = "World";
String hello_world1 = new String("HelloWorld");
String hello_world2 = hello + world;
String hello_world3 = "Hello"+"World";
String hello_world4 = "HelloWorld";
System.out.println(hello_world1 == hello_world2);
System.out.println(hello_world1 == hello_world3);
System.out.println(hello_world1 == hello_world4);
System.out.println(hello_world2 == hello_world3);
System.out.println(hello_world2 == hello_world4);
System.out.println(hello_world3 == hello_world4);
}
}
在说以上问题之前,我们先了解一下JVM的基本结构(Java8)
方法区:保存类的结构信息(XXX.Class)的区域
栈:保存程序运行时临时变量、对象的引用和方法的区域
本地方法栈:保存java调用本地方法的区域
程序计数器:进行程序运行指令选择的区域
元空间:保存描述数据的数据信息的区域
堆:保存我们new对象的区域
以上描述为简易描述,详细内容这里不做重点
String类型在内存中的存储位置有两处
- StringTable
- 堆
有了以上的了解,我们就可以基本解决文章开头的问题了
- String hello = “Hello”;
执行本语句时会先去StringTable中查看是否存在"Hello",如果不存在会在StringTable中创建一个
- String world = “World”;
同上
- String hello_world1 = new String(“HelloWorld”);
new 出一个String对象,该语句会在堆内存中创建一个"HelloWorld"的字符串对象
- String hello_world2 = hello + world;
这一个就有点意思了。它是由两个StringTable变量组合而成的,反编译一下看看
红框内的代码就是String hello_world2 = hello + world;的运行情况,下面我们来进行一下解读
第6行 new了一个StringBuilder类型的对象
第10行 执行StringBuilder的init方法进行初始化
第14行 执行append方法参数为String类型,没错这就是我们的append(hello)
第18行 执行append方法参数为String类型,这就是我们的append(world)
第21行 执行StringBuilder的toString()方法,来看下源码
他又new了一个String类型的对象
所以由上可以看出String hello_world2 = hello + world;
其实就是相当于
String hello_world2 = new StringBuilder().append(hello).append(world).toString();
也是在堆中新建了一个String对象
- String hello_world3 = “Hello”+“World”;
那直接取StringTable中的字符串呢?又会是怎样的?
这里就不得不提JAVA8的编译期优化机制了,在编译期间,由于"Hello"与"World"都已经是确定不变的,所以java会直接将"Hello"+"World"变为"HelloWorld"常量,在常量池中查找,找不到在常量池中创建新的常量
- String hello_world4 = “HelloWorld”;
这个就很明白了,直接在StringTable中查找"HelloWorld"常量,因为之前已经创建过了,所以一定能找到。
最终以上代码在内存中的情况如下图:
至此,以上问题的答案就算非常明晰了。
答案公布:
hello_world1 == hello_world2 false
hello_world1 == hello_world3 false
hello_world1 == hello_world4 false
hello_world2 == hello_world3 false
hello_world2 == hello_world4 false
hello_world3 == hello_world4 true