JVM-字符串底层实现原理

1.什么字符串会进入字符串常量池 1. 直接写的字面量
2. 字面量的拼接结果(注意:如果字符串拼接中有变量则结果不会进入字符串常量池)
3. 调用String的intern方法可以将String存入字符串常量池
2. 字面量的拼接原理 有如下列展示代码:
JVM-字符串底层实现原理文章插图
在ideal中查看编译的class文件:
JVM-字符串底层实现原理文章插图
总结:
以上面两个文件我们可以看出 , 这种字符串的拼接在编译期间就已经优化了 , 直接就合并为一个字符串;并且这个字符串存放在字符串常量池
3. 字符串和变量拼接原理 java源码:
JVM-字符串底层实现原理文章插图
利用jclasslib查看main方法的字节码命令:
如果以下名词不明白请阅读请自行了解学习java虚拟机栈;
【JVM-字符串底层实现原理】我们可以发现就简单的两行代码 , 产生了这么多的字节码命令;
在代码中我简单解释了每一行的作用 。
JVM-字符串底层实现原理文章插图
总结:
以上内容我们可以知道字符串拼接实际上就是创建了一个StringBuilder对象然后向里面append内容 , 最后调用toString方法获得结果
3.1 为什么结果没有存储在常量池 从上述字节码指令已经知道了字符串拼接结果是StringBuilder的toString方法的结果 , 那么 toString里面具体做了什么事情 , 又是为什么结果不在常量池?
以下StringBuilder.toString的源码以及字节码指令:
JVM-字符串底层实现原理文章插图
总结:
以上代码可以很好的解释实际上最终是调用了的构造方法传入一个数组 , 那么最终的结果肯定也就在咱们的堆空间 。
4. 为什么字符串拼接效率低 4.1. 源码准备 首先编写两个方法一个使用字符串拼接 , 一个使用StringBuilder进行拼接
JVM-字符串底层实现原理文章插图
4.2.字节码指令层面解析 以上代码的执行时间长短我就不在重复测试了相信大家都会 , 接下来我们来一起看看这两个方法字节码指令 。
concatStrByDefault方法的字节码指令如下:
简单解释下循环是在33行的goto指令调到第5行这样不断循环;并且在11行也就是循环中不断的通
过new创建了StringBuilder对象 , 也就是循环了多少次就创建了多少个StringBuilder对象 , 并且如果大家看了我之前写字符串拼接原理 , 在StringBuilder的toString方法中还new 了一个String对象;这里这么多对象的创建就必然需要垃圾回收效率自然就低了
JVM-字符串底层实现原理文章插图
concatStrByBuilder方法的字节码指令:
此处循环在27行的goto指令跳到12行 , 并且循环之间是没有创建新对象的 , 紧紧只是调用了 append方法 , 这里就能很明显的看出这种方式比普通拼接少创建了很多的对象
JVM-字符串底层实现原理文章插图
4.3. 总结 拼接效率低的主要原因也就是每一次拼接都创建了一个StringBuilder对象 , 并且在赋值是又需要调用toString方法 , 而toString方法的实现里面有new了一个String对象 , 所以拼接的效率很低 。