美文网首页
java String创建字符串对象——面试java基础

java String创建字符串对象——面试java基础

作者: small瓜瓜 | 来源:发表于2019-06-20 23:08 被阅读0次

    在一次面试中,被问到这方面的问题,搞得我一脸蒙逼,那时候还没去了解JVM,为了以后不再出现这样的情况,我就在这里好好梳理一下String创建会创建多少个对象呢?

    先看代码

    public static void main(String[] args) {
            String str1 = "abc";
            String str2 = "a" + "b" + "c";
            System.out.println("结果1:" + (str1 == str2));
            String str3 = "a";
            String str4 = str3 + "bc";
            System.out.println("结果2:" + (str1 == str4));
            System.out.println("结果3:" + (str1 == str4.intern()));
            final String str5 = "a";
            String str6 = str5 + "bc";
            System.out.println("结果4:" + (str1 == str6));
        }
    

    代码运行结果:

    结果1:true
    结果2:false
    结果3:true
    结果4:true
    

    上面的运行结果需要从两个方面来说明:
    一:java编译器
    二:java字符串常量池

    java编译器

    我们来看看java编译器将上面的源码编译成了什么样子。(反编译结果)

    public static void main(String[] args) {
            String str1 = "abc";
            String str2 = "abc";
            System.out.println("结果1:" + (str1 == str2));
            String str3 = "a";
            String str4 = str3 + "bc";
            System.out.println("结果2:" + (str1 == str4));
            System.out.println("结果3:" + (str1 == str4.intern()));
            String str5 = "a";
            String str6 = "abc";
            System.out.println("结果4:" + (str1 == str6));
        }
    

    源代码和编译后的代码有很多不同点。str2和str6都变成了直接赋值为"abc",而str4却没有变化,这里也是java新手不太清楚的地方,其实由于常量字符串是在编译的时候就是可以被确定的,又因"a","b"和"c"都是字符串常量,因此变量str2的值在编译时就可以确定,同理因为str5被final关键字修饰,也相当于字符串常量,因此变量str6的值也在编译时就可以确定,代码编译后就和String str="abc"一样了。
    也是因为上面的原因str4没有改变,因为str4并不能在编译期确定。

    java字符串常量池

    在执行代码String str1 = "abc"时,JVM先去字符串常量池中查找,看是否已经存在值为”abc”的对象,如果存在,则不再创建新的对象,而直接返回已存在对象的引用;反之,则先创建一个新的对象,然后加入到字符串池中,再将其引用返回。

    String str1 = "abc";  // 会创建一个新的对象"abc"在字符串常量池中
    String str2 = "abc";  // 因为字符串常量池中已经存在"abc",所以不会创建对象
    

    这样结果1true,就可以理解了

    String str3 = "a";  // 会创建一个新的对象"abc"在字符串常量池中
    /* 
    下面这行代码一共会创建三个对象:
      1. 会在字符串常量池中创建一个"bc"对象
      2. str3与 "bc" 进行字符串连接时,底层通过StringBuffer进行连接,生成一个
        StringBuffer对象(StringBuffer内部字符不考虑)
      3. 然后通过StringBuffer的append方法连接,通过toString()方法,将StringBuffer对象
        转为String,此时会产生一个新的堆内存地址,str4指向这个新的内存地址。
    */
    String str4 = str3 + "bc"; 
    // 因为str4在堆内存变量中,str1在字符串常量池中,所以==地址比较为false
    System.out.println("结果2:" + (str1 == str4));
    // str4.intern() 返回在字符串常量池中的"abc"引用,就和str1是同一对象,为true
    System.out.println("结果3:" + (str1 == str4.intern()));
    

    字符串相加推荐文章

    看完上面的代码相信您已经对字符串创建对象个数有了一定的了解,接下来我们再来看看另一种情况。

    /*
    下面的代码,一共会创建两个对象:
      1. 在字符串常量池中创建"abc"对象
      2. 在堆中创建的原实例字符串对象
    */
    String str1 = new String("abc");
    // str1只是java栈中的对象引用
    

    注意:String类型的引用是存在栈里。而字符串"abc"是存在字符串常量池中

    // 在字符串常量池中创建一个"abc"对象
    String str1 = "abc";
    // 由于"abc"已经在字符串常量池中已经存在,所以不会再创建。
    // 使用new关键字创建字符串,一定会在堆中创建一个实例,所以下面代码会创建一个对象
    String str2 = new String("abc");
    // str1只是java栈中的对象引用
    

    注意:String类型的引用是存在栈里。而字符串"abc"是存在字符串常量池中

    下面提升难度

      public static void main(String[] args) {
            String str1 = "a" + new String("b");
            String str2 = "ab";
            System.out.println(str1 == str2);
            String str3 = str2 + "c";
            str3.intern();
            String str4 = "abc";
            System.out.println(str3 == str4);
        }
    

    运行结果:

    false
    true
    

    注意:上面的运行结果和jdk版本有关,1.7和1.8都是上面的结果,1.7以下不是
    上面的结果重点就是intern方法的作用,这里我只是抛砖引玉,想了解更多的读者可以看看下面的这篇博客:
    深入解析String#intern

    笔者个人能力有限,如有错误,请联系我修改。

    相关文章

      网友评论

          本文标题:java String创建字符串对象——面试java基础

          本文链接:https://www.haomeiwen.com/subject/vcqsqctx.html