深入解析Java编程中的StringBuffer与StringBuider_java

String 的值是不可变的,每次对String的操作都会生成新的String对象,不仅效率低,而且耗费大量内存空间。

StringBuffer类和String类一样,也用来表示字符串,但是StringBuffer的内部实现方式和String不同,在进行字符串处理时,不生成新的对象,在内存使用上要优于String。

StringBuffer 默认分配16字节长度的缓冲区,当字符串超过该大小时,会自动增加缓冲区长度,而不是生成新的对象。

StringBuffer不像String,只能通过 new 来创建对象,不支持简写方式,例如:

StringBuffer str1 = new StringBuffer(); // 分配16个字节长度的缓冲区
StringBuffer str2 = =new StringBuffer(512); // 分配512个字节长度的缓冲区
// 在缓冲区中存放了字符串,并在后面预留了16个字节长度的空缓冲区
StringBuffer str3 = new StringBuffer(www.weixueyuan.net);

StringBuffer类的主要方法

StringBuffer类中的方法主要偏重于对于字符串的操作,例如追加、插入和删除等,这个也是StringBuffer类和String类的主要区别。实际开发中,如果需要对一个字符串进行频繁的修改,建议使用 StringBuffer。
1) append() 方法

append() 方法用于向当前字符串的末尾追加内容,类似于字符串的连接。调用该方法以后,StringBuffer对象的内容也发生改变,例如:

StringBuffer str = new StringBuffer(“biancheng100”);
str.append(true);

则对象str的值将变成”biancheng100true”。注意是str指向的内容变了,不是str的指向变了。

字符串的”+“操作实际上也是先创建一个StringBuffer对象,然后调用append()方法将字符串片段拼接起来,最后调用toString()方法转换为字符串。

这样看来,String的连接操作就比StringBuffer多出了一些附加操作,效率上必然会打折扣。

但是,对于长度较小的字符串,”+“操作更加直观,更具可读性,有些时候可以稍微牺牲一下效率。
2)  deleteCharAt()

deleteCharAt() 方法用来删除指定位置的字符,并将剩余的字符形成新的字符串。例如:

StringBuffer str = new StringBuffer("abcdef");
str. deleteCharAt(3);

该代码将会删除索引值为3的字符,即”d“字符。

你也可以通过delete()方法一次性删除多个字符,例如:

StringBuffer str = new StringBuffer("abcdef");
str.delete(1, 4);

该代码会删除索引值为1~4之间的字符,包括索引值1,但不包括4。
3) insert() 方法

insert() 用来在指定位置插入字符串,可以认为是append()的升级版。例如:

StringBuffer str = new StringBuffer("abcdef");
str.insert(3, "xyz");

最后str所指向的字符串为 abcdxyzef。
4) setCharAt() 方法

setCharAt() 方法用来修改指定位置的字符。例如:

StringBuffer str = new StringBuffer("abcdef");
str.setCharAt(3, 'z');

该代码将把索引值为3的字符修改为 z,最后str所指向的字符串为 abczef。

以上仅仅是部分常用方法的简单说明,更多方法和解释请查阅API文档。
String和StringBuffer的效率对比

为了更加明显地看出它们的执行效率,下面的代码,将26个英文字母加了10000次。

public class Demo {
  public static void main(String[] args){
    String fragment = "abcdefghijklmnopqrstuvwxyz";
    int times = 10000;

    // 通过String对象
    long timeStart1 = System.currentTimeMillis();
    String str1 = "";
    for (int i=0; i<times; i++) {
      str1 += fragment;
    }
    long timeEnd1 = System.currentTimeMillis();
    System.out.println("String: " + (timeEnd1 - timeStart1) + "ms");

    // 通过StringBuffer
    long timeStart2 = System.currentTimeMillis();
    StringBuffer str2 = new StringBuffer();
    for (int i=0; i<times; i++) {
      str2.append(fragment);
    }
    long timeEnd2 = System.currentTimeMillis();
    System.out.println("StringBuffer: " + (timeEnd2 - timeStart2) + "ms");
  }
}

运行结果:

String: 5287ms
StringBuffer: 3ms

结论很明显,StringBuffer的执行效率比String快上千倍,这个差异随着叠加次数的增加越来越明显,当叠加次数达到30000次的时候,运行结果为:

String: 35923ms
StringBuffer: 8ms

所以,强烈建议在涉及大量字符串操作时使用StringBuffer。
StringBuilder类

StringBuilder类和StringBuffer类功能基本相似,方法也差不多,主要区别在于StringBuffer类的方法是多线程安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。

StringBuffer、StringBuilder、String中都实现了CharSequence接口。

CharSequence是一个定义字符串操作的接口,它只包括length()、charAt(int index)、subSequence(int start, int end) 这几个API。

StringBuffer、StringBuilder、String对CharSequence接口的实现过程不一样,如下图所示:

可见,String直接实现了CharSequence接口;StringBuilder 和 StringBuffer都是可变的字符序列,它们都继承于AbstractStringBuilder,实现了CharSequence接口。
总结

线程安全:

StringBuffer:线程安全
StringBuilder:线程不安全

速度:
一般情况下,速度从快到慢为 StringBuilder > StringBuffer > String,当然这是相对的,不是绝对的。

使用环境:
操作少量的数据使用 String;
单线程操作大量数据使用 StringBuilder;
多线程操作大量数据使用 StringBuffer。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, stringbuffer
StringBuider
stringbuider、stringbuffer、stringbuffer 清空、java stringbuffer、stringbuffer的用法,以便于您获取更多的相关知识。

时间: 2024-09-20 05:29:47

深入解析Java编程中的StringBuffer与StringBuider_java的相关文章

深入解析Java编程中面向字节流的一些应用_java

文件输入输出流 文件输入输出流 FileInputStream 和 FileOutputStream 负责完成对本地磁盘文件的顺序输入输出操作. [例]通过程序创建一个文件,从键盘输入字符,当遇到字符"#"时结束,在屏幕上显示该文件的所有内容 import java.io.*; class ep10_5{ public static void main(String args[]){ char ch; int data; try{ FileInputStream a=new FileI

深入解析Java编程中final关键字的使用_java

在Java中声明属性.方法和类时,可使用关键字final来修饰.final变量即为常量,只能赋值一次:final方法不能被子类重写:final类不能被继承.1.final成员声明 final 字段有助于优化器作出更好的优化决定,因为如果编译器知道字段的值不会更改,那么它能安全地在寄存器中高速缓存该值.final 字段还通过让编译器强制该字段为只读来提供额外的安全级别.  1.1关于final成员赋值1)在java中,普通变量可默认初始化.但是final类型的变量必须显式地初始化.   2)fin

深入解析Java编程中的boolean对象的运用_java

只能是true或false两个值之一的变量就是布尔(boolean)类型变量,true和false是布尔型直接量.你可以用下面的语句定义一个名称为state的布尔型变量: boolean state=true     该语句用true值对变量state进行了初始化.你也可以使用赋值语句为一个boolean型变量赋值.例如,语句, state=false     设置变量state的值为false.     目前,我们除了为布尔变量赋值外,还不能进行更多的操作,但正像你在下一章中将要看到的,布尔型

深入解析Java编程中final关键字的作用_java

final class当一个类被定义成final class,表示该类的不能被其他类继承,即不能用在extends之后.否则在编译期间就会得到错误. package com.iderzheng.finalkeyword; public final class FinalClass { } // Error: cannot inherit from final class PackageClass extends FinalClass { } Java支持把class定义成final,似乎违背了面

深入解析Java编程中接口的运用_java

接口的本质--接口是一种特殊的抽象类,这种抽象类里面只包含常量和方法的定义,而没有变量和方法的实现. 抽象类所具有的一些东西接口可以具有,假如一个抽象类里面所有的方法全都是抽象的,没有任何一个方法需要这个抽象类去实现,并且这个抽象类里面所有的变量都是静态(static)变量,都是不能改变(final)的变量,这时可以把这样的抽象类定义为一个接口(interface).把一个类定义成一个接口的格式是把声明类的关键字class用声明接口的关键字interface替换掉即可. 接口(interface

深入解析Java编程中的抽象类_java

Java程序用抽象类(abstract class)来实现自然界的抽象概念.抽象类的作用在于将许多有关的类组织在一起,提供一个公共的类,即抽象类,而那些被它组织在一起的具体的类将作为它的子类由它派生出来.抽象类刻画了公有行为的特征,并通过继承机制传送给它的派生类.在抽象类中定义的方法称为抽象方法,这些方法只有方法头的声明,而用一个分号来代替方法体的定义,即只定义成员方法的接口形式,而没有具体操作.只有派生类对抽象成员方法的重定义才真正实现与该派生类相关的操作. 在各子类继承了父类的抽象方法之后,

深入解析Java编程中方法的参数传递_java

在阅读本文之前,根据自己的经验和理解,大家可以先思考并选择一下Java函数的参数传递方式: A. 是按值传递的? B. 按引用传递的? C. 部分按值部分按引用? 此处暂不宣布正确答案,我们通过一个简单的例子让大家自己找答案: 1. 先定义一个类型Value public static class Value { private String value = "value"; public String getValue() { return value; } public void

解析Java编程中对于包结构的命名和访问_java

包的命名包的名字应该避免与其他包冲突,所以选择一个既有意义又唯一的名字是包设计的一个重要方面.但是全球的程序员都在开发包,根本就没有办法获知谁采用了什么包名,因此选择唯一的包名是一个难题.如果我们确定某个包只在我们的组织内部使用,那么我们就可以让内部仲裁者(internal arbiter)来确保项目之间不会发生名字冲突. 但是对于整个世界而言,这种方法是不实际的.包的标识符都是简单的名字,一种比较好的能够确保包名唯一的方法是使用Internet域名.如果我们所就职的公司的名字为Magic.ln

完全解析Java编程中finally语句的执行原理_java

可不能小看这个简单的 finally,看似简单的问题背后,却隐藏了无数的玄机.接下来我就带您一步一步的揭开这个 finally 的神秘面纱.问题分析首先来问大家一个问题:finally 语句块一定会执行吗? 很多人都认为 finally 语句块是肯定要执行的,其中也包括一些很有经验的 Java 程序员.可惜并不像大多人所认为的那样,对于这个问题,答案当然是否定的,我们先来看下面这个例子. 清单 1. public class Test { public static void main(Stri