String的不可变性、以及涉及到的字符串常量池和字符串拼接内部实现的剖析

来源:互联网 发布:湖北旅游 知乎 编辑:程序博客网 时间:2024/06/07 17:59

1.String a="a"+"b"+"c"在内存中创建几个对象?

这个问题涉及到了字符串常量池和字符串拼接
String a="a"+"b"+"c"
通过编译器优化后,得到的效果是
String a="abc"

此时,如果字符串常量池中存在abc,则该语句并不会创建对象,只是讲字符串常量池中的引用返回而已

如果字符串常量池中不存在abc,则会创建并放入字符串常量池,并返回引用,此时会有一个对象进行创建


2.Java中的字符串常量池

Java中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";另一种就是使用new这种标准的构造对象的方法,如String str = new String("droid");,这两种方式我们在代码编写时都经常使用,尤其是字面量的方式。然而这两种实现其实存在着一些性能和内存占用的差别。
这一切都是源于JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池

工作原理当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用

使用new创建当我们使用了new来构造字符串对象的时候,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。

注意:1.字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的
2.字符串常量池中存放的是引用还是对象,这个问题是最常见的。字符串常量池存放的是对象引用,不是对象。在Java中,对象都创建在堆内存中。

优缺点

字符串常量池的好处就是减少相同内容字符串的创建,节省内存空间。

如果硬要说弊端的话,就是牺牲了CPU计算时间来换空间。CPU计算时间主要用于在字符串常量池中查找是否有内容相同对象的引用。不过其内部实现为HashTable,所以计算成本较低。



3.Java细节:字符串的拼接

Java中仅有的重载运算符:在Java中,唯一被重载的运算符就是字符串的拼接相关的:+,+=。除此之外,Java设计者不允许重载其他的运算符。

拼接剖析-编译器的优化处理

既然Sting对象不可变,那么多个(三个及以上)字符串拼接必然产生多余的中间String对象。真的会有上面的性能代价么,字符串拼接这么常用,没有特殊的处理优化么,答案是有的,这个优化进行在编译器编译.java到bytecode时。
一个Java程序如果想运行起来,需要经过两个时期,编译时和运行时。在编译时,Java 编译器(Compiler)将java文件转换成字节码。在运行时,Java虚拟机(JVM)运行编译时生成的字节码。通过这样两个时期,Java做到了所谓的一处编译,处处运行。
Java编译器做的优化,当Java编译器遇到字符串拼接的时候,会创建一个StringBuilder对象,后面的拼接,实际上是调用StringBuilder对象的append方法。


1 0
原创粉丝点击