Java 字符串拼接原理分析


目录

  • Java 字符串拼接原理分析
  • 【示例】常量做字符串拼接
  • 【示例】变量做字符串拼接操作



对于常量做字符串拼接操作时,对于编译期就能确定的值,编译器会将值合并。

【示例】常量做字符串拼接

public class Test {
	public static void main(String[] args) {
		test01();
		test02();
	}
	/**
	 * 直接字符串常量拼接,对于编译期就能确定的值,编译器会将值合并
	 * String hw = "hello" + "world";
	 * 我们反编译字节码文件,就会将看到 : String hw = "helloworld";
	 * 
	 * 所以hw == helloWorld 输出true
	 */
	public static void test01() {
		String hw = "hello" + "world"; // 等于:String hw = "helloworld";
		String helloWorld = "helloworld";
		System.out.println(hw == helloWorld); // 输出:true
	}
/**
	 * String hw = h + "world";虽然包含变量h的运算,但是编译器
	 * 对final变量在编译期能确定其值,会发生宏替换,即:h变量替换成其值"hello",
	 * 然后编译器会对直接量字串直接合并
	 * String hw = h + "world";在编译完后就变成了 String hw = "helloworld";
	 * 
	 * 所以hw == helloWorld 输出true
	 */
	public static void test02() {
		final String h = "hello"; // final修饰的是常量
		String hw = h + "world"; // 等于:String hw = "helloworld";
		String helloWorld = "helloworld";
		System.out.println(hw == helloWorld); // 输出:true
	}
}
/**
 * 使用“+”连接符完成字符串拼接操作的底层分析(重点)
 * 情况一:两个字符串都是常量时,使用“+”来完成拼接操作
 *    底层:因为常量保存的内容不可改变,也就是编译时期就能确定常量的值,因此为了提高字符串的拼接效率,所以就在编译时期就完成了拼接操作。
 *    例如1:String str = "hello" + "world"; 编译之后:String str = "helloworld";
 *    例如2:final String STR1 = "hello"; final String STR2 = "world"; String str = STR1 + STR2; 编译之后:String str = "helloworld";
 */
public class TestStringConcatPrinciple01 {
    /**
     * 情况一:两个字符串都是常量时,使用“+”来完成拼接操作
     */
    public static void main(String[] args) {
        String str = "hello" + "world"; // 编译之后:String str = "helloworld";
        System.out.println(str);
    }
}

在jd-gui中,将上面的代码进行反编译得到结果如下:

java 字符相加 java 字符串相加原理_开发语言

/**
 * 使用“+”连接符完成字符串拼接操作的底层分析(重点)
 * 情况一:两个字符串都是常量时,使用“+”来完成拼接操作
 *    底层:因为常量保存的内容不可改变,也就是编译时期就能确定常量的值,因此为了提高字符串的拼接效率,所以就在编译时期就完成了拼接操作。
 *    例如1:String str = "hello" + "world"; 编译之后:String str = "helloworld";
 *    例如2:final String STR1 = "hello"; final String STR2 = "world"; String str = STR1 + STR2; 编译之后:String str = "helloworld";
 */
public class TestStringConcatPrinciple02 {
    /**
     * 情况一:两个字符串都是常量时,使用“+”来完成拼接操作
     */
    public static void main(String[] args) {
        final String STR1 = "hello";
        final String STR2 = "world";
        String str = STR1 + STR2;
        // 以上三行代码,在编译之后的结果就是:String str = "helloworld";
        System.out.println(str);
    }
}

在jd-gui中,将上面的代码进行反编译得到结果如下:

java 字符相加 java 字符串相加原理_java 字符相加_02

对于变量做字符串拼接操作时,由于相加的变量中存放的是字符串的地址引用,因为在编译时无法确切地知道其他具体的值,也就没有办法对其进行优化处理,这时为了达到连接的效果,其内部采用了StringBuilder的机制进行处理(JDK1.5中新增的,我这里没有JDK1.4,估计在JDK1.4下采用的是StringBuffer),将他们都 append进去,最后用toString 输出。

【示例】变量做字符串拼接操作

public class Test {
/**
	 * hw在编译期并不能确定值,因为str是变量,JVM在运行期才能确定其值。
	 * 在运行期时,进行字串拼接生成新的字串对象,通过javap -c Test查看虚拟机
	 * 指令,我们发现“String hw = str + "world";”其实等效于:
	 * StringBuilder sb = new StringBuilder();
	 * sb.append(str);
	 * sb.append("world");
	 * String hw = sb.toString();
	 *
	 * 所以hw == helloWorld 输出false
	 */
	public static void main(String[] args) {
		String str = "hello";
		String hw = str + "world";
		String helloWolrd = "helloworld";
		System.out.println(hw == helloWolrd); // 输出:false 
	}
}
/**
 * 情况二:其中一个为字符串变量时,使用“+”来完成拼接操作
 *    底层:因为编译时期无法确定变量的值,因此其中一个为字符串变量的拼接操作,那么肯定不是在编译时期完成,而是在运行时期来完成的,并且实现步骤如下。
 *    例如:分析“String hw = str + "world"”代码的底层实现过程
 *      第一步:创建一个StringBuilder对象,用于字符串的拼接操作。
 *         --> StringBuilder sb = new StringBuilder();
 *      第二步:调用sb对象的append()方法,用于拼接str字符串。
 *         --> sb.append(str);
 *      第三步:调用sb对象的appen d()方法,用于拼接"world"。
 *         --> sb.append("world");
 *      第四步:调用sb对象的toString()方法,然后再去做赋值操作
 *         --> String hw = sb.toString();
 */
public class TestStringConcatPrinciple03 {

    public static void main(String[] args) {
        String str = "hello";
        String hw = str + "world";
        System.out.println(str);
    }
}

在jd-gui中,将上面的代码进行反编译得到结果如下:

java 字符相加 java 字符串相加原理_java_03

javap -c Test查看虚拟机指令

java 字符相加 java 字符串相加原理_eclipse_04