浅析StringBuilder和StringBuffer

来源:互联网 发布:2016开淘宝店铺流程图 编辑:程序博客网 时间:2024/05/21 20:18

我们在开发中一般会看见,或是用到以上两个操作字符串的类。

那么我们在使用的过程中是否考虑过到底何时何地该如何使用这两个类呢?

现在我们就来系统的分析一下这两个类的作用和区别之处!

首先二话不说:我们来查询他们分别对应的API文档,

         首先:StringBuilder。在api文档中是这样来描述它的!

一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快

StringBuilder 上的主要操作是 append insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串生成器中。append 方法始终将这些字符添加到生成器的末端;而 insert 方法则在指定的点添加字符。

例如,如果 z 引用一个当前内容为 "start" 的字符串的生成器对象,则该方法调用 z.append("le") 将使字符串生成器包含 "startle",而 z.insert(4, "le") 将更改字符串生成器,使之包含 "starlet"

通常,如果 sb 引用 StringBuilder 的实例,则 sb.append(x) sb.insert(sb.length(), x) 具有相同的效果每个字符串生成器都有一定的容量。只要字符串生成器所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区。如果内部缓冲区溢出,则此容量自动增大

StringBuilder 的实例用于多个线程是不安全的。如果需要这样的同步,则建议使用 StringBuffer

那么我们就对于以上的文字来展开我们对它的学习和认识!

首先我们依依对这文档的关键字 红色标注的文字进行解释

1.  可变的字符序列:可变的字符序列,如果知道String的特性我们就知道当我们每定义一个字符串的时候 系统就会开辟一个空间* 然而在我们使用连加+ 比如说:String a=b+c+d+f+g+h+j;的时候整个系统的效率就会降低这也就是我们在实际的开发过程中为什么不建议甚至是不允许使用多个连+的原因了 具体为什么效率降低 这里就不在为大家讲解那么可变的字符序列就是系统在你定义的一开始就为这个对象在内存中开辟了一段很长的空间 那么使用这个对象的append追加的时候系统就无需再开辟新的空间 直接将其拉到已有的空间当中。

2.  StringBuffer 和简单替换 用于在字符串缓存区被单个线程访问 StringBuffer在设计之初是可以利用它实现同步操作的 就是说在几个线程同时访问这个内存单元的时候 可以实现好的效果,但是在大多数的开发候中我们一般只会设计到单线程对其的操作,所以为了提高速度所以在此的基础上提出了StringBuilder这个类 因为它只针对于单个线程使用的。

3.  Append 我们查询api文档

StringBuilder

append(boolean b)
          
boolean 参数的字符串表示形式追加到序列。

 StringBuilder

append(char c)
          
char 参数的字符串表示形式追加到此序列。

 StringBuilder

append(char[] str)
          
char 数组参数的字符串表示形式追加到此序列。

 StringBuilder

append(char[] str, int offset, int len)
          
char 数组参数的子数组的字符串表示形式追加到此序列。

 StringBuilder

append(CharSequence s)
          
向此 Appendable 追加到指定的字符序列。

 StringBuilder

append(CharSequence s, int start, int end)
          
将指定 CharSequence 的子序列追加到此序列。

 StringBuilder

append(double d)
          
double 参数的字符串表示形式追加到此序列。

 StringBuilder

append(float f)
          
float 参数的字符串表示形式追加到此序列。

 StringBuilder

append(int i)
          
int 参数的字符串表示形式追加到此序列。

 StringBuilder

append(long lng)
          
long 参数的字符串表示形式追加到此序列。

 StringBuilder

append(Object obj)
          
追加 Object 参数的字符串表示形式。

 StringBuilder

append(String str)
          
将指定的字符串追加到此字符序列。

 StringBuilder

append(StringBuffer sb)
          
将指定的 StringBuffer 追加到此序列。

我们可以看到有这么重载append方法 我们在看看insert方法

StringBuilder

insert(int offset, boolean b)
          
boolean 参数的字符串表示形式插入此序列中。

 StringBuilder

insert(int offset, char c)
          
char 参数的字符串表示形式插入此序列中。

 StringBuilder

insert(int offset, char[] str)
          
char 数组参数的字符串表示形式插入此序列中。

 StringBuilder

insert(int index, char[] str, int offset, int len)
          
将数组参数 str 子数组的字符串表示形式插入此序列中。

 StringBuilder

insert(int dstOffset, CharSequence s)
          
将指定 CharSequence 插入此序列中。

 StringBuilder

insert(int dstOffset, CharSequence s, int start, int end)
          
将指定 CharSequence 的子序列插入此序列中。

 StringBuilder

insert(int offset, double d)
          
double 参数的字符串表示形式插入此序列中。

 StringBuilder

insert(int offset, float f)
          
float 参数的字符串表示形式插入此序列中。

 StringBuilder

insert(int offset, int i)
          
int 参数的字符串表示形式插入此序列中。

 StringBuilder

insert(int offset, long l)
          
long 参数的字符串表示形式插入此序列中。

 StringBuilder

insert(int offset, Object obj)
          
Object 参数的字符串表示形式插入此字符序列中。

 StringBuilder

insert(int offset, String str)
          
将字符串插入此字符序列中。

我们可以看到这两种方法的基本结构式一一对应的 就是在基础上加上了 int offset 这个int变量 这就是插入到指定的位置上。方法很简单 这里就不在一一为大家讲解了!最后说一下其实在Stringbuilder中就是存在一个动态数组的 就是说在一开始 初始化这个类的时候 就定义了一个动态的数组 这个数组室友大小的在调用append的这个方法的时候就相当于在这个动态数组中add插入了一个string类型 那么在调用insert的这个方法是 就使用了System.arrayCopy的这个方法 将String字符串copy到新的数组中。在这里我们就看见了 java设计的巧妙之处!

4sb.append(x) sb.insert(sb.length(), x) 具有相同的效果每个字符串生成器都有一定的容量

这里我们显然可以知道 append的这个方法是在数组的后面进行追加的 insert是在指定的位置追加的 然而指定了数组的最后一个位置追加 就相当于是append的的效果一样所以如果你看到某人使用了说sb.append(sb.lenth(),x)这样的方法的时候 你就可以完全抨击他 垃圾!

4.   自动增大 在这里的意思就是我们以上所说的 其实StringBuilder其实在内部定义了一个动态数组 使用过动态数组的同学都知道 每当add方法的时候就会判断是否超出的了本身的大小如果超出 就重新增加大小!

5.   同步 以上我们所说了 StringBuilder是用于单线程的 这是一种固定的机制 那么要运用于多线程中 我们就需要使用StringBuffer

那么下面我们就来讨论一下这个StringBuffer对象

线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。

可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。

StringBuffer 上的主要操作是 append insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。

例如,如果 z 引用一个当前内容为 "start" 的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含 "startle",而 z.insert(4, "le") 将更改字符串缓冲区,使之包含 "starlet"

通常,如果 sb 引用 StringBuilder 的一个实例,则 sb.append(x) sb.insert(sb.length(), x) 具有相同的效果。

当发生与源序列有关的操作(如源序列中的追加或插入操作)时,该类只在执行此操作的字符串缓冲区上而不是在源上实现同步。

每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量自动增大。 JDK 5 开始,为该类补充了一个单个线程使用的等价类,即 StringBuilder。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。

以上的我们就不必再细细去追究了 主要看红色标注的位置!