深入java String JVM对String对象的连接优化 一(源码分析)
2017-05-10 16:41
639 查看
上一篇文章我们总结了final关键字需要注意的地方和JVM对final关键字的优化。我看《阿里巴巴Java开发手册》,发现(四.OOP规则)第17条对String有进行说明。这一篇文章分析一下String、StringBuffer和StringBuilder的用法和源码。原创不易,转载请注明出处:http://blog.csdn.net/yabay2208
阿里巴巴的文档规范
String使用以及源码分析
String到底相等吗
String在重载运算符“+”的时候到底发生了什么(下一篇)
StringBuffer使用以及源代码分析(下一篇)
StringBuilder使用以及源代码分析(下一篇)
![](http://img.blog.csdn.net/20170510144242897?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
String类的源码:
String类为我们提供了大量的方法,大家可以自行参考api文档来看,我接一个图作说明:
![](http://img.blog.csdn.net/20170510153844940?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
例子1:值在编译期确定(相等)
![](http://img.blog.csdn.net/20170510155323124?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
运行结果:
![](http://img.blog.csdn.net/20170510155345734?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
分析:因为例子中的 a和b中的”helloWorld”都是字符串常量,它们在编译期就被确定了,所以a=b,他们的地址相同。而”hello”和”World”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以c也同样在编译期就被解析为一个字符串常量,所以c也是常量池中”helloWorld”的一个引用。所以我们得出a=b=c;
例子2:值在编译期无法确定(不相等)
![](http://img.blog.csdn.net/20170510160746862?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
运行结果:
![](http://img.blog.csdn.net/20170510160812644?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
分析:因为例子中的 a的”helloWorld”是字符串常量,在编译期就被确定了,值被放到常量池中共享,而b在编译期没有办法确定下来,需要在运行期才能确定,所以b的值在堆内存中,c也一样,所以他们不相等
例子3:jvm在编译期对字符串拼接的优化(相等)
![](http://img.blog.csdn.net/20170510161439450?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
运行结果:
![](http://img.blog.csdn.net/20170510161456411?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
分析:在程序编译期,JVM就将常量字符串的”+”连接优化为连接后的值,”helloWorld” + 2经编译器优化后在.class中就已经是”helloWorld2”。在编译期其字符串常量的值就确定下来,故上面程序最终的结果为true。
例子4:涉及引用操作,编译期值无法确定(不相等)
![](http://img.blog.csdn.net/20170510162102849?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
运行结果:
![](http://img.blog.csdn.net/20170510162144021?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
**分析:**JVM对于字符串引用:由于在字符串的”+”连接中,有字符串引用存在,而引用的值(句柄)在程序编译期是无法确定的,即a + 2无法被编译器优化,只有在程序运行期来动态分配内存保存好值,并将连接后的新地址赋给b。所以上面程序的结果为false。
例子5:涉及引用操作,编译期值确定(相等)
![](http://img.blog.csdn.net/20170510162758824?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
运行结果:
![](http://img.blog.csdn.net/20170510162808891?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
分析:和[4]中唯一不同的是b字符串加了final修饰。(对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中)。所以此时的b + “World”和”hello” + “World”效果是一样的。故上面程序的结果为true。
例子6:涉及引用操作,编译期值无法确定(不相等)
![](http://img.blog.csdn.net/20170510163529391?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
运行结果:
![](http://img.blog.csdn.net/20170510163539219?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFiYXkyMjA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
分析:和[5]中唯一不同的是字符串b虽然声明成了final,但是他的值无法在编译期确定,需要在运行期才能确定。将方法的返回值动态连接并分配地址给c, 程序的结果为false。
限于篇幅原因:我们将部分内容放到下一篇。
阿里巴巴的文档规范
String使用以及源码分析
String到底相等吗
String在重载运算符“+”的时候到底发生了什么(下一篇)
StringBuffer使用以及源代码分析(下一篇)
StringBuilder使用以及源代码分析(下一篇)
一:阿里巴巴的文档规范
二:String使用以及源码分析
String是不可改变类(基本类型的包装类都是不可改变的)的典型代表,也是Immutable设计模式的典型应用,String变量一旦初始化后就不能更改,禁止改变对象的状态,从而增加共享对象的坚固性、减少对象访问的错误,同时还避免了在多线程共享时进行同步的需要。字符串是常量,它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享String类的源码:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
String类为我们提供了大量的方法,大家可以自行参考api文档来看,我接一个图作说明:
三:String相等吗
为了说明String是否相等,我们会从常量池出发和内存出发,对比这些值是否相等。例子1:值在编译期确定(相等)
运行结果:
分析:因为例子中的 a和b中的”helloWorld”都是字符串常量,它们在编译期就被确定了,所以a=b,他们的地址相同。而”hello”和”World”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以c也同样在编译期就被解析为一个字符串常量,所以c也是常量池中”helloWorld”的一个引用。所以我们得出a=b=c;
例子2:值在编译期无法确定(不相等)
运行结果:
分析:因为例子中的 a的”helloWorld”是字符串常量,在编译期就被确定了,值被放到常量池中共享,而b在编译期没有办法确定下来,需要在运行期才能确定,所以b的值在堆内存中,c也一样,所以他们不相等
例子3:jvm在编译期对字符串拼接的优化(相等)
运行结果:
分析:在程序编译期,JVM就将常量字符串的”+”连接优化为连接后的值,”helloWorld” + 2经编译器优化后在.class中就已经是”helloWorld2”。在编译期其字符串常量的值就确定下来,故上面程序最终的结果为true。
例子4:涉及引用操作,编译期值无法确定(不相等)
运行结果:
**分析:**JVM对于字符串引用:由于在字符串的”+”连接中,有字符串引用存在,而引用的值(句柄)在程序编译期是无法确定的,即a + 2无法被编译器优化,只有在程序运行期来动态分配内存保存好值,并将连接后的新地址赋给b。所以上面程序的结果为false。
例子5:涉及引用操作,编译期值确定(相等)
运行结果:
分析:和[4]中唯一不同的是b字符串加了final修饰。(对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中)。所以此时的b + “World”和”hello” + “World”效果是一样的。故上面程序的结果为true。
例子6:涉及引用操作,编译期值无法确定(不相等)
运行结果:
分析:和[5]中唯一不同的是字符串b虽然声明成了final,但是他的值无法在编译期确定,需要在运行期才能确定。将方法的返回值动态连接并分配地址给c, 程序的结果为false。
限于篇幅原因:我们将部分内容放到下一篇。
相关文章推荐
- 深入java String拼接和StringBuffer、StringBuilder(分析源码)
- 对象参数深入分析jQuery.prototype.init选择器源码 Strut2教程-java教程
- JAVA随笔篇二(深入分析JAVA简单类型、String和对象的值传递和引用传递)
- Java源码分析:深入探讨Iterator模式及Java 5.0中改进的for循环
- Java源码分析:深入探讨Iterator模式
- Java源码分析:深入探讨Iterator模式
- Java源码分析:深入探讨Iterator模式
- 深入研究java对String字符串对象的创建以及管理【转帖】
- 深入研究java对String字符串对象的创建以及管理
- 深入研究java对String字符串对象的创建以及管理
- Java源码分析:深入探讨Iterator模式 (转载)
- 深入研究java对String字符串对象的创建以及管理
- Java源码分析:深入探讨Iterator模式
- Java源码分析:深入探讨Iterator模式
- Java源码分析:深入探讨Iterator模式-Java基础-Java-编程开发
- 深入研究java对String字符串对象的创建以及管理
- 深入研究java对String字符串对象的创建以及管理
- Java深入了解String对象
- 深入研究java对String字符串对象的创建以及管理
- Java源码分析:深入探讨Iterator模式