• String+、intern()、字符串常量池


    字符串连接符 “+”及字符串常量池实验、字符串final属性

    结果预览

    public class StrTest{
    	public static void main(String[] args){
    		String str1="hello";
    		String str2="hello"+"wiaoong";  //常量 编译器直接优化为 hellowiaoong
    		String str3=str1+"wiaoong";	
    		System.out.println(str3==str2); //false
    		
    		final String str4="hello";
    		String strFinal=str4+"wiaoong";
    		System.out.println(strFinal==str2);	//true
    		
    		String str6="hello";
    		String str7=new String("hello");
    		System.out.println(str7==str6); //false
    		String str8=str7.intern();
    		System.out.println(str6==str8); //true
    
                    String str11="123";
    		String str12=str11;
    		str11+="456";
    		System.out.println(str12);    //123
    		System.out.println(str11);    //456
    	}
    }
    

    场景一:编译器优化

    public class StrTest{
    	public static void main(String[] args){
    		String str1="hello";
    		String str2="hello"+"wiaoong";
    		String str3=str1+"wiaoong";	
    	}
    }
    

    Jvm编译指令:javap -c StrTest.class
    这些指令我也是一知半解,但是不妨碍我们分析发生了什么,如果有更好的指令参考文章请留言分享。
    附上一份JVM指令博文:JVM指令博客
    结果分析:
    编译后的JVM指令集

      public static void main(java.lang.String[]);
        Code:
           0: ldc           #2                  // String hello
           2: astore_1
           3: ldc           #3                  // String hellowiaoong
           5: astore_2
           6: new           #4                  // class java/lang/StringBuilder
           9: dup
          10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
          13: aload_1
          14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          17: ldc           #7                  // String wiaoong
          19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          22: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
          25: astore_3
          26: return
    

    观察指令可以得知:

    • str2在编译时已经被编译器给优化了,也就是说连接符“+”连接的是两个常量时 如 "a"+"b", 和 "ab"是等价的
    • str3在编译的时候Jvm新建了一个StirngBuilder对象,并且分布把常量"wiaoong"和变量str1进行了append操作,最后返回了StirngBuilder.toString()给str3,
      也就是说连接符“+”连接中存在变量时,会通过StringBuilder构建新的对象。
      由上可知,str3==str2 为false.

    场景二:编译器优化

     public class StrTest{
    	public static void main(String[] args){
    		final String str4="wiaoong";
    		String str5="hello"+"wiaoong";
    		String str3="hello"+str4;	
    		System.out.println(str5==str3); //true
    	}
    }     
    

    编译后的JVM指令集

    public static void main(java.lang.String[]);
        Code:
           0: ldc           #2                  // String hellowiaoong
           2: astore_2
           3: ldc           #2                  // String hellowiaoong
           5: astore_3
           6: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
           9: aload_2
          10: aload_3
          11: if_acmpne     18
          14: iconst_1
          15: goto          19
          18: iconst_0
          19: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
          22: return
    

    由上可知,这是常量的一种.

    场景三:字符串常量池

    public class StrTest{
    	public static void main(String[] args){
    		String str6="hello";
    		String str7=new String("hello");
    		System.out.println(str7==str6); //false
    		String str8=str7.intern();
    		System.out.println(str6==str8); //true
    	}
    }
    

    编译后的JVM指令集

     public static void main(java.lang.String[]);
        Code:
           0: ldc           #2                  // String hello
           2: astore_1
           3: new           #3                  // class java/lang/String
           6: dup
           7: ldc           #2                  // String hello
           9: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
          12: astore_2
          13: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
          16: aload_2
          17: aload_1
          18: if_acmpne     25
          21: iconst_1
          22: goto          26
          25: iconst_0
          26: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
          29: aload_2
          30: invokevirtual #7                  // Method java/lang/String.intern:()Ljava/lang/String;
          33: astore_3
          34: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
          37: aload_1
          38: aload_3
          39: if_acmpne     46
          42: iconst_1
          43: goto          47
          46: iconst_0
          47: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
          50: return
    

    由上可知:

    • new 创建字符串时,检测到常量池中已经存在字面量“hello”,直接返回常量池中的应用给new构建新的对象

    • intern()能完成字符串主动入池操作,如果字符串已经存在字符串常量池中,就返回常量池中字符串的引用地址
      str6初始化后,常量池中已经存在hello了,执行intern()就直接返回引用. 即JVM指令集中的步骤7 ldc 操作,所以str6==str8为true

    场景4:字符串final分析

    public class StrTest{
    	public static void main(String[] args){
    		String str11="123";
    		String str12=str11;
    		str11+="456";
    		System.out.println(str12); //123
    		System.out.println(str11); //123456
    	}
    }
    

    分析:
    str11+="456"这行代码创建了一个新的对象,并且把str11指向了新的匿名String对象的堆内存地址,而str11的堆内存内的内容是没有变化的。
    上图:
          


    这里又衍生出一个String str=a+b+c+d;创建了几个对象的面试常见问题?

    分析:

    public StringBuilder() {
            super(16);
        }
    
    public StringBuffer() {
            super(16);
        }
    

    初始化char[]大小是16,如果超过这个长度则会进行char[]扩容,new一个新的char[]

    执行toString()是又new 了一个String

    算上JVM自动创建的StringBuilder(),结果是2-3个
    如果字符长常量池中没有这个字符串,那么又会新建一个对象

    作者:往霄龙
    求其上者得其中,求其中者得其下
  • 相关阅读:
    面试笔试题目集
    [vs2010]:fatal error C1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "StdAfx.h"”?
    [数据库] SQLite常见问题解答
    安卓学习资料总结39
    Android 学习资料总结40
    python变量的定义和使用
    python运算符
    python的注释
    print输出函数
    python数据类型转换
  • 原文地址:https://www.cnblogs.com/JQKA/p/11906145.html
Copyright © 2020-2023  润新知