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

全部评论

相关推荐

dongsheng66:如果想进大厂的话,在校经历没必要占这么大篇幅,可以把专业技能单独放一个专栏写,可以加个项目经历
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务