Java字符串拼接原理
JVM-字符串底层实现原理前置内容java虚拟机栈1.那些字符串会进入字符串常量池直接写的字面量字面量的拼接结果(注意:如果字符串拼接中有变量则结果不会进入字符串常量池)调用String的intern方法可以将String存入字符串常量池2. 字面量的拼接原理java源码package com.hgy;import java.util.Arrays;import java.util.List;pu
·
JVM-字符串拼接原理
- 前置内容
1.那些字符串会进入字符串常量池
- 直接写的字面量
- 字面量的拼接结果(注意:如果字符串拼接中有变量则结果不会进入字符串常量池)
- 调用String的intern方法可以将String存入字符串常量池
2. 字面量的拼接原理
-
java源码
package com.hgy; import java.util.Arrays; import java.util.List; public class hello { public static void main(String[] args) { String a = "hello" + " world"; } }
-
在idea中查看编译后的class文件
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.hgy; public class hello { public hello() { } public static void main(String[] args) { String a = "hello world"; } }
-
结论:
- 以上面两个文件我们可以看出,这种字符串的拼接在编译期间就已经优化了,直接就合并为一个字符串;并且这个字符串存放在字符串常量池
3. 字符串和变量拼接原理
-
java源码
package com.hgy; import java.util.Arrays; import java.util.List; public class hello { public static void main(String[] args) { String v = "java"; String a = v + "hello" + " world"; } }
-
利用jclasslib查看main方法的字节码命令
- 如果一下名词不明白请阅读java虚拟机栈
- 我们可以发现就简单的两行代码,产生了这么多的字节码命令;在代码中我简单解释了每一行的作用,
0 ldc #2 <java> // 从字符串常量池加载java 2 astore_1 // 存储常量到索引为1的局部变量表中 3 new #3 <java/lang/StringBuilder> //给StringBuilder对象分配内存空间 6 dup 7 invokespecial #4 <java/lang/StringBuilder.<init>> //执行StringBuilder的构造方法 10 aload_1 //获取局部变量表索引为1的引用地址, 11 invokevirtual #5 <java/lang/StringBuilder.append> //把上面加载的内容作为参数传递给append方法 14 ldc #6 <hello world> // 从字符串常量池加载hello world 16 invokevirtual #5 <java/lang/StringBuilder.append> //把上面加载的内容作为参数传递给append方法 19 invokevirtual #7 <java/lang/StringBuilder.toString> //调用toString方法 22 astore_2 //结果存储到局部变量表 23 return
-
以上内容我们可以知道字符串拼接实际上就是创建了一个StringBuilder对象然后向里面append内容,最后调用toString方法获得结果
3.1 为什么结果没有存储在常量池
-
从上述字节码指令已经知道了字符串拼接结果是StringBuilder的toString方法的结果,那么toString里面具体做了什么事情,又是为什么结果不在常量池?
-
一下是StringBuilder.toString的源码以及字节码指令
@Override public String toString() { // Create a copy, don't share the array //此处value为一个char数组【我的jdk版本为jdk8】 return new String(value, 0, count); }
0 new #80 <java/lang/String> 3 dup 4 aload_0 5 getfield #234 <java/lang/StringBuilder.value> 8 iconst_0 9 aload_0 10 getfield #233 <java/lang/StringBuilder.count> 13 invokespecial #291 <java/lang/String.<init>> 16 areturn
-
以上代码可以很好的解释实际上最终是调用了String的构造方法传入一个char数组,那么最终的结果肯定也就在咱么的堆空间
更多推荐
所有评论(0)