最近学习到字符串,整理了一下String,StringBuffer,StringBuilder相关知识
### 1. String
String 类位于 java.lang 包中。String 对象创建后则不能被修改,是不可变的,所谓的修改其实是创建了新的对象,所指向的内存空间不同。
~~~
String str1 = "xiaosi";
str1 = "欢迎你 " + str1;
System.out.println(str1); // 欢迎你 xiaosi
~~~
通过观察运行结果可以看见str1变量输出确实改变了,但是为什么一直说String对象是不可变的呢? 我们其实被表象给欺骗了,JVM是这样解析这段代码的:首先创建对象str1,赋予xiaosi,然后再创建一个新的对象用来执行第二行代码,str1指向了这个新对象,原对象没有发生改变,由于这种机制,每当用String操作字符串时,实际上是在不断的创建新对象,而原来的对象就会变为垃圾被GC回收掉。
![](https://box.kancloud.cn/2016-03-18_56eba2a73fde6.jpg)
这样做是否会降低运行效率呢?看起来好像修改一个代码单元要比创建一个新字符串更加简洁。答案是:也对,也不对。通过拼接"欢迎你"和"xiaosi"来创建一个新字符串的效率确实不高。但是,不可变字符却有一个有点:编译器可以让字符串达到共享。
为了弄清楚具体的工作方式,可以想象将各种字符串放入公共的字符串存储池中,字符串变量指向字符串存储池中相应位置。如果复制一个字符串变量,原始字符串与复制的字符串变量共享相同的字符。
Java设计者认为共享带来的高效率远远胜于提取,拼接字符串所带来的低效率。查看一下程序你就会发现:很少需要修改字符串,而是往往需要对字符串进行比较。
### 2.StringBuffer
String和StringBuffer他们都可以存储和操作字符串,即包含多个字符的字符串数据。String类是字符串常量,是不可更改的常量。而StringBuffer是字符串变量,它的对象是可以扩充和修改的。
~~~
// 创建一个空的StringBuffer类的对象。
public StringBuffer()
// 创建一个长度为 参数length 的StringBuffer类的对象。
public StringBuffer( int length )
~~~
其是线程安全的可变字符序列。一个类似于 String 的字符串缓冲区。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符添加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量自动增大。
### 3.StringBuilder
从 JDK 5 开始,为该类补充了一个单个线程使用的等价类,即 StringBuilder。StringBuffer和StringBuilder类功能基本相似,主要区别在于StringBuffer类的方法是多线程、安全的,而 StringBuilder不是线程安全的。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。对于经常要改变值的字符串应该使用 StringBuffer和StringBuilder类。
### 4.总结
(1)一般情况下,速度从快到慢:StringBuilder > StringBuffer > String,这种比较是相对的,不是绝对的。
(2)当字符串缓冲被多个线程使用时,JVM不能保证StringBuilder的操作是安全的,虽然速度快,但是StringBuffer是可以保证是正确操作的。大多数情况下是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的。
- 前言
- [Hibernate开发之路](1)Hibernate配置
- [Hibernate开发之路](2)Hibernate问题
- [Hibernate开发之路](3)基础配置
- [Hibernate开发之路](4)ID生成策略
- [Hibernate开发之路](5)联合主键
- [设计模式实践之路](1)单例模式
- [Java]UDP通信的简单例子
- [Java]套接字地址InetAddress讲解
- [Java开发之路](1)final关键字
- [Java开发之路](2)Java字符串
- [Java开发之路](3)Java常用类
- [Java开发之路](4)String、StringBuffer与StringBuilder详解
- [Java开发之路](5)异常详解
- [Java开发之路](6)File类的使用
- [Java开发之路](7)RandomAccessFile类详解
- [Java开发之路](8)输入流和输出流
- [Java开发之路](9)对象序列化与反序列化
- [Java开发之路](10)DOM解析XML文档
- [Java开发之路](11)SAX解析XML文档
- [Java开发之路](12)JDOM和DOM4J解析XML文档
- [Java开发之路](14)反射机制
- [Java开发之路](15)注解
- [Java开发之路](16)学习log4j日志
- [Java开发之路](18)关于Class.getResource和ClassLoader.getResource的路径问题
- [Java开发之路](19)Long缓存问题
- [Java开发之路](20)try-with-resource 异常声明
- [Java开发之路](21)Comparator与Comparable
- [Java]Java工程师成神之路
- [细说Java](1)图说字符串的不变性
- [细说Java](2)Java中字符串为什么是不可变的
- [细说Java](3)创建字符串是使用" "还是构造函数?