• String是否相等、new的时候创建了几个对象等问题详解


    问题一

    这段代码创建了几个对象?

    String str1 = new String("aa");
    

    答案是两个
    “aa”对象String对象

    Java代码在编译成Class文件之后,Class文件中包含以下内容

    其中有一项是常量池
    常量池在Class文件被加载的时候,会被加载进内存中的方法区中的运行时常量池,而运行时常量池里就包括字符串常量池,Class文件中的字符串在类加载时就会加载到字符串常量池中去

    在这里插入图片描述

    不过在周志明老师在深入java虚拟机中有说到,到了JDK1.7时,字符串常量池就被移出了方法区,转移到了堆里了。当然这并不影响我们之后的解读

    而代码

    String str1 = new String("aa");
    

    中的"aa"就是被加载进去的字符串,我们可以看看Class文件
    在这里插入图片描述
    (1). 这里的aa在之后类加载的时候
    会在字符串常量池里创建一个 "aa"对象,这是第一个对象
    (2). 类加载完成了之后,那就要开始正式执行代码了
    执行该行代码时new一个"aa"的String对象存放在Java堆中,这是第二个对象
    (3). 创建完第二个对象后,虚拟机栈上的str1将会指向第二个对象,也就是堆上的对象

    问题二

    结果是true还是false?

     String str1 = new String("aa");
     String str2 = "aa";
     System.out.println(str1 == str2);
    

    答案很明显是false,因为两个变量指向的地址不同,一个指向字符串常量池,一个指向堆上的对象,而==比较的就是地址。

    问题三

    那这个的结果是true还是false?

     String str1 = new String("aa");
     str1.intern();
     String str2 = "aa";
     System.out.println(str1 == str2);
    

    首先我们来了解一下intern方法
    intern的处理是 先判断字符串常量是否在字符串常量池中,如果存在直接返回该常量,如果没有找到,说明该字符串常量在堆中,则处理是把堆区该对象的引用加入到字符串常量池中,以后别人拿到的是该字符串常量的引用,实际存在堆中。

    也就是说现在字符串常量池中的"aa"实际上是指向堆上的String对象的?
    所以结果是true?

    并不是,结果还是false

    我们在之前问题一中,

    String str1 = new String("aa");
    

    这段代码创建了两个对象,而第一个就是在字符串常量池中的,而intern方法在判断时会发现字符串常量池中已经存在"aa"对象了,所以它就不用把字符串常量池中添加一个指向堆上的String对象的地址了
    所以最后intern方法只是返回了"aa"对象,并没有做任何修改

    所以还是str1指向堆,str2指向字符串常量池,结果为false

    那要怎么样才能true?

    问题四

    String str3 = new String("a") + new String("a");
    str3.intern();
    String str4 = "aa";
    System.out.println(str3 == str4);
    

    这里打印的结果就是true了

    这里的str3生成的方式不再是new String(“aa”);
    而是new String(“a”) + new String(“a”);拼接起来的方式,因此在编译后,Class文件中的常量池写入的是"a"对象而不是"aa"对象,如下图:
    在这里插入图片描述
    因此intern方法在判断时会发现字符串常量池中并没有"aa"对象,
    于是它就把堆中String对象的引用加入到字符串常量池中
    之后创建str4的时候,str4就会先在字符串常量池中先查找有没有"aa",于是它找到了intern放入的引用,并把这个引用赋给str4
    所以str3和str4都是同一个引用,str3==str4,为true

    问题五

    那么这段代码又创建了几个对象?

    String str3 = new String("a") + new String("a");
    

    答案是五个

    因为使用+号的String字符串拼接,底层其实都是先创建一个StringBuilder对象,然后调用append方法把要+的字符串都append进去,最后toString创建一个新的String对象如下图:
    在这里插入图片描述
    红色的地方就是new出来对象的语句,而绿色则是两次append
    四个红色一共四个对象,再加上字符串常量池上创建的"a"对象,一共五个

    这也正是为什么阿里巴巴代码规范中不建议在for循环里使用+号拼接字符串
    在这里插入图片描述

    String str1 = "aaa";
    String str2 = "bbb";
    String str4 = str1 + str2;
    

    这个的String str4 = str1 + str2;创建了两个对象,StringBuilder和toString时生成的String对象

    那下面这段呢?是"aaa"对象加"bbb"对象加StringBuilder和toString时生成的String对象一共四个对象吗?

    String str5 = "aaa" + "bbb";
    

    很可惜这段只创建了1个对象
    java编译器在编译这段的时候做了优化,实际上"aaa"+"bbb"会先拼接成"aaabbb"之后才开始编译,也就是说这段代码等于是String str5 = "aaabbb"
    如下图:(code里面没有任何new操作)
    在这里插入图片描述

  • 相关阅读:
    随笔
    第一次随笔
    团队战day02-接口
    团队战day01-初步搭建UI
    团队战start-确定项目以及介绍
    团队—易软
    找回感觉的练习
    第五次作业-团队作业-团队组建
    第四次博客作业-结对项目
    java第九次作业
  • 原文地址:https://www.cnblogs.com/fatmanhappycode/p/12231199.html
Copyright © 2020-2023  润新知