位于上海,服务全国!

位于上海,服务全国!

探索Java字符串的对等类:Java StringBuilder和Java StringBuffer

作者:admin 分类: 时间:2017-02-23 18:41:27 点击量:451

Java提供了三种详尽的方案来处理在Object类支持下的字符串。表示不可变字符序列的类被称为String,StringBuffer类表示线程安全的可变序列的字符和StringBuilder,表示不保证同步的可变序列字符。这些类定义了其中的许多方法,为深层次的继承提供基础。这篇文章试图提供他们的存在背后的感觉。

概述
在深入研究字符串类之前,让我们来看看它们与Java API库中定义的其他接口的关联。

public final class String
extends Object
implements Serializable, Comparable<String>,
   CharSequence


public final class StringBuffer
extends Object
implements Serializable, CharSequence

public final class StringBuilder
extends Object
implements Serializable, CharSequence
String类通过Serializable, Comparable和CharSequence实现了三个接口。并且StringBuffer和StringBuilder类实现了Serializable和CharSequence。 它们都是最终类,意味着它们不能被继承或子类化。 这些类的一个显着的优点就是来自接口的实现。 他们可以简要地被说明如下。

可序列化

实现此接口的类用于标识类的状态,以在其对象存在的过程中遵循序列化或反序列化的语义。

以下文章提供了有关序列化概念的更多详细介绍:

CharSequence
此接口提供了对不同种类的char值的序列的统一,在只读访问框架内,诸如由基本多语言平面(BMP)或代理表示的。unicode编码的更改标准允许字符以超过16位的表示。 因此,BMP表示从U + 0000到U + FFFF的字符值。 因为Java使用基于UTF-16的字符数组String和StringBuffers的补充字符由一对char值表示,范围从\ uD800到\ uDBFF和\ uDC00到\ uDFFF,分别称为高替代和低替代。 因此,char值包括BMP和UTF-16编码的替代码点。

有兴趣的读者可能会发现有关Unicode字符处理有趣的文章“如何创建多语言JasperReport”。

在接口中声明的方法遵循均匀性约定。但是,实现CharSequence对象之间的比较结果通常是未定义的,因为由不同类定义的对象不能保证测试它们与另一个实例的相等性能力。它们可能在编码方案的标准下不一致。 这就是为什么任意CharSequence不应该用作地图中的集合或键元素的原因。

可比性
这个接口强加了与类相关联的项目自然排序原理。唯一的方法,compareTo(),由接口声明的行为与自然排序的原则是与等号是一致的。 将Comparable接口与String类一起使用可以检查序列的各个字符,尤其是字符串比较和其他相关操作。 请参阅本文“使用Java Comparator”以获得更全面的视图。

除了与StringBuffer和StringBuilder相关联的接口之外,还有另一个微妙的接口,通过未公开的(Java API Docs)抽象类(称为AbstractStringBuilder)与这两个类相关联。 这个接口称为Appendable。

Appendable
此接口通常由打算接收格式化输出的类实现。 附加的字符必须符合UTF-16编码方案。

字符串类
Java中的字符串既不是基本字符也不是字符数组。 它基本上是一个表示一系列字符常量的类。 然而,有趣的事实是,它表现为较原始,并且在编程的大部分时间,我们以相同的方式处理它。 我们可以声明一个String变量,创建一个String数组,或者使用的赋值几乎类似于原始类型。事实是,在Java编程中,String是如此常见的行为,但打算像原始类型。

在双引号中声明的字符串常量,例如:

System.out.println("Hello String");
它实际上是一个String对象,虽然它可能不是这样。String对象可以以许多方式构造,例如:

String str1="Hello String";
Concatenate two or more strings:

String str2="Hello" +" String";
String str3=str2+"."
通过在String类中定义被称为length()的方法测量字符串大小的相等性。

String类对于大多数字符串处理操作方便,例如比较两个字符串,连接两个字符串,搜索子字符串,或者除了像原始数据类型一样使用字符串对象外,还有更改字符串中的字母大小写。 但问题是,当我们创建一个字符串对象时,我们也保证它的不变性。 也就是说,组成字符串的字符不能更改。 然而,这不是一个缺点,但是String类不方便。

因此,Java提供了两个名为StringBuffer和StringBuilder的类,使我们能够创建可修改的字符串。 这两个类没有限制创建一个即使在创建后也可以改变的字符串。

StringBuffer和StringBuilder
StringBuffer和StringBuilder类的功能非常相似,并且在它们中定义了一些相同的方法。 与字符串的固定长度不可变字符序列相反,这两个类代表可增长和同时可编辑的字符序列。 我们总是可以在这些类表示的已经存在的字符串中追加或插入一个子字符串。 空间将被自动分配;事实上,这些类维护了某些预先分配的字符,实际上需要这些字符作为主动扩展的一种形式。

存在三种类型字符串类的原因可能是由于在开发Java API库过程中产生想法的改变;尽管如此,他们在开始理解时有些混乱地服务于他们的目的。 但奇怪的是,因为StringBuffer和StringBuilder类都有类似的能力,但非常明显地从它们的父类派生。

为了更好地理解,让我们比较这三个类和什么时候使用它们。

在Java编程中,除了创建一个不可变字符串之外,我们经常引用一个String对象用于多个变量。 这种类型的引用非常有利于Java编译器的优化,因为对象确实改变了。 这种类型的场景适合使用String对象。 在我们需要频繁进行字符串操作的情况下(如串联或其他字符串修改),使用StringBuilder对象更有效。

但是,StringBuilder不是线程安全的。 因此,如果我们需要多个线程来访问相同的动态字符串信息,我们必须使用StringBuffer。 然而StringBuffer和StringBuilder有相同的功能,它们不同只是StringBuffer具有线程安全性,而StringBuilder没有。 如果按照是否有效率来对两者进行选择,那么就要选择StringBuilder。

这里是一个示例代码来说明StringBuilder和StringBuffer之间的效率。


package org.mano.example;


public class Benchmark {


   public static void main(String[] args) {
      System.out.println("StringBuffer:");
      testStringBuffer();
      System.out.println("StringBuilder:");
      testStringBuilder();
   }


   public static void testStringBuffer() {


      StringBuffer stringBuffer = new StringBuffer();
      long startTime = System.currentTimeMillis();
      for (int i = 0; i < 100000; i++)
         stringBuffer.append(i);
      long endTime = System.currentTimeMillis();
      System.out.println("Elapsed time=" +
         (endTime - startTime)+"ms");
   }


   public static void testStringBuilder() {
      StringBuilder stringBuilder = new StringBuilder();
      long startTime = System.currentTimeMillis();
      for (int i = 0; i < 100000; i++)
         stringBuilder.append(i);
      long endTime = System.currentTimeMillis();
      System.out.println("Elapsed time=" +
         (endTime - startTime)+"ms");
   }


}
输出:
StringBuffer:
Elapsed time=32ms
StringBuilder:
Elapsed time=11ms
这里,我们不讨论通过这些类提供的方法细节。 有兴趣的读者可仔细阅读Java API文档。


结论
StringBuilder更多是StringBuffer的自发设计,并且应该更多使用String对象,特别是在效率方面。 另一方面,StringBuffer应该可以勉强地被使用,并且只当有多个线程使用字符串缓冲区的机会时。 简而言之,我们可以得出以下结论:

StringBuffer + (Single thread) = StringBuilder;
StringBuilder + (multiple thread) = StringBuffer;