别再问我 new 字符串创建了几个对象了!我来证明给你看!(下)

简介: 别再问我 new 字符串创建了几个对象了!我来证明给你看!

扩展知识


我们知道 String 是 final 修饰的,也就是说一定被赋值就不能被修改了。但编译器除了有字符串常量池的优化之外,还会对编译期可以确认的字符串进行优化,例如以下代码:


public static void main(String[] args) {
    String s1 = "abc";
    String s2 = "ab" + "c";
    String s3 = "a" + "b" + "c";
    System.out.println(s1 == s2);
    System.out.println(s1 == s3);
}


按照 String 不能被修改的思想来看,s2 应该会在字符串常量池创建两个字符串“ab”和“c”,s3 会创建三个字符串,他们的引用对比结果也一定是 false,但其实不是,他们的结果都是 true,这是编译器优化的功劳。


同样我们使用 javac StringExample.java 先编译代码,再使用 javap -c StringExample 命令查看编译的代码如下:


警告: 文件 ./StringExample.class 不包含类 StringExample
Compiled from "StringExample.java"
public class com.example.StringExample {
  public com.example.StringExample();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
  public static void main(java.lang.String[]);
    Code:
       0: ldc           #7                  // String abc
       2: astore_1
       3: ldc           #7                  // String abc
       5: astore_2
       6: ldc           #7                  // String abc
       8: astore_3
       9: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      12: aload_1
      13: aload_2
      14: if_acmpne     21
      17: iconst_1
      18: goto          22
      21: iconst_0
      22: invokevirtual #15                 // Method java/io/PrintStream.println:(Z)V
      25: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      28: aload_1
      29: aload_3
      30: if_acmpne     37
      33: iconst_1
      34: goto          38
      37: iconst_0
      38: invokevirtual #15                 // Method java/io/PrintStream.println:(Z)V
      41: return
}


从 Code 3、6 可以看出字符串都被编译器优化成了字符串“abc”了。


总结


本文我们通过 javap -v XXX 的方式查看编译的代码发现 new String 首次会在字符串常量池中创建此字符串,那也就是说,通过 new 创建字符串的方式可能会创建 1 个或 2 个对象,如果常量池中已经存在此字符串只会在堆上创建一个变量,并指向字符串常量池中的值,如果字符串常量池中没有相关的字符,会先创建字符串在返回此字符串的引用给堆空间的变量。我们还将了字符串常量池在 JDK 1.7 和 JDK 1.8 的变化以及编译器对确定字符串的优化,希望能帮你正在的理解字符串的比较。


相关文章
|
6月前
|
存储 编译器 Linux
【字符串探秘:手工雕刻的String类模拟实现大揭秘】(下)
【字符串探秘:手工雕刻的String类模拟实现大揭秘】
|
6月前
|
存储 编译器
【字符串探秘:手工雕刻的String类模拟实现大揭秘】(上)
【字符串探秘:手工雕刻的String类模拟实现大揭秘】
|
6月前
|
编译器 C语言 C++
【字符串探秘:手工雕刻的String类模拟实现大揭秘】(中)
【字符串探秘:手工雕刻的String类模拟实现大揭秘】
|
5月前
|
存储 数据库
【随手记】顺序I/O和随机I/O的定义和区别
【随手记】顺序I/O和随机I/O的定义和区别
157 1
|
NoSQL Java 数据库
解释afterPropertiesSet方法的用处
解释afterPropertiesSet方法的用处
|
测试技术
字符串a和他许久未见面的同父异母的b(模拟)(思维)
字符串a和他许久未见面的同父异母的b(模拟)(思维)
78 0
通过代码加解析的方式带领大家分析 :数组与指针的关系
通过代码加解析的方式带领大家分析 :数组与指针的关系
83 0
通过代码加解析的方式带领大家分析 :数组与指针的关系
|
Java Apache
集合的特别要注意地方哈
《系统设计》系列
78 0
|
Java Spring
阿粉写了八千多字,只为讲透参数合法性验证)(四)
最近很多读者给阿粉留言,说怎么好久没看到我的文章了,这里说一下。 由于公众号不再按时间线排序,所以你会发现有时候能看到几天前的文章,这不是出BUG,是公众号的一次改变。 至于排序的具体标准是啥,阿粉也不太清楚,大概和你打开某个公众号的频率有关。 所以如果你想第一时间收到阿粉的文章,可以点击Java极客技术的的头像,再点右上角三个点,进去设置一下【星标】。
阿粉写了八千多字,只为讲透参数合法性验证)(四)
|
Java 数据库连接 Spring
阿粉写了八千多字,只为讲透参数合法性验证)(三)
最近很多读者给阿粉留言,说怎么好久没看到我的文章了,这里说一下。 由于公众号不再按时间线排序,所以你会发现有时候能看到几天前的文章,这不是出BUG,是公众号的一次改变。 至于排序的具体标准是啥,阿粉也不太清楚,大概和你打开某个公众号的频率有关。 所以如果你想第一时间收到阿粉的文章,可以点击Java极客技术的的头像,再点右上角三个点,进去设置一下【星标】。
阿粉写了八千多字,只为讲透参数合法性验证)(三)