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中,将上面的代码进行反编译得到结果如下:
/**
* 使用“+”连接符完成字符串拼接操作的底层分析(重点)
* 情况一:两个字符串都是常量时,使用“+”来完成拼接操作
* 底层:因为常量保存的内容不可改变,也就是编译时期就能确定常量的值,因此为了提高字符串的拼接效率,所以就在编译时期就完成了拼接操作。
* 例如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中,将上面的代码进行反编译得到结果如下:
对于变量做字符串拼接操作时,由于相加的变量中存放的是字符串的地址引用,因为在编译时无法确切地知道其他具体的值,也就没有办法对其进行优化处理,这时为了达到连接的效果,其内部采用了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中,将上面的代码进行反编译得到结果如下:
javap -c Test查看虚拟机指令