欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

Java中String、StringBuffer、StringBuilder知识要点讲解,

来源: javaer 分享于  点击 46032 次 点评:159

Java中String、StringBuffer、StringBuilder知识要点讲解,


String 字符串常量 StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全)

String

Strings are constant; their values cannot be changed after they are created.

这是JavaAPI中对于String的定义,就是说String是常量,一旦定义就无法改变。说到常量就不得不提到Java中的字符串常量池,通过String的俩种创建方法来进行了解

String俩种创建方式区别

Java中字符串对象创建有两种形式,一种为字面量形式,如String str = “abc”;,另一种就是使用new这种标准的构造对象的方法,如String str = new String(“abc”);

当Java中出现第一种字面量形式创建字符串时,JVM首先会在常量池中进行查找是否存在相同字符串对象内容的引用,如果存在,那么直接将新创建的对象指向该引用地址,如果不存在则创建新的引用对象,并把该引用对象放入常量池

public class Test {
 public static void main(String[] args) {
  String str1 = "abc";
  String str2 = "abc";
  System.out.println(str1 == str2); // true
 }
}

通过以上代码可以看到结果为true 也就是说str1 str2 指向的是相同的地址。现在将代码改变:

public class Test {
 public static void main(String[] args) {
  String str1 = "abc";
  str1 = "xyz";
  String str2 = "abc";
  System.out.println(str1 == str2); // false
 }
}

当JVM看到"xyz",在字符串常量池创建新的String对象存储它,再把新建的String对象的引用返回给str1,所以这时候str1 指向的是xyz ,而abc 还是存在于字符串常量池中,其值并不能被改变,所以返回false

接下来继续将代码改为以下:

public class Test {
 public static void main(String[] args) {
  String str1 = "abc";
  str1 = "xyz";
  String str2 = "abc";
  System.out.println(str1 == str2); // false
  String str3 = new String("abc");
  System.out.println(str2 == str3); // false
 }
}

通过new 来创建一个新的String对象str3 ,这个过程是首先,JVM在常量池中找是否存在abc ,如果找到,不做任何事情,如果没找到,在常量池中创建该对象;接着由于有new 关键字,会在栈内存空间(不是字符串常量池)中创建str3 对象,并指向堆内存空间(不是字符串常量池)中的abc ,接下来进行str2 == str3 比较的时候肯定不是引用的同一个对象,所以返回false

所以说使用new创建String对象过程中是产生了俩个对象

另外Java中还提供了如何将new创建的对象手动放入常量池,看以下代码:

public class Test {
 public static void main(String[] args) {
  String str1 = "abc";
  str1 = "xyz";
  String str2 = "abc";
  System.out.println(str1 == str2); // false
  String str3 = new String("abc");
  System.out.println(str2 == str3); // false
  String str4 = str3.intern();
  System.out.println(str2 == str4); // true
 }
}

这样结果就返回的是true

StringBuilder VS StringBuffer

通过上面的介绍我们简单的了解了String是不可变的,是一个常量,因此当我们使用String来构建一个动态的字符串对于内存的开销是特别大的,因为对于每个字符串我们都得分配新的内存空间

所以在Java开发初就提供了StringBuffer JavaAPI对于StringBuffer 的说明是

A thread-safe, mutable sequence of characters.

这个可变的类来创建动态的字符数组,而这个只需要分配一次内存,这与String相比是节省了大量的内存空间,另外,由于其是线程安全的,所以其所有的public 方法都是synchronized ,而这样的设计就会导致,当开发人员是在单线程的环境中时,就会增加额外的开销,而且大多数对于StringBuffer 的使用基本上都是在单线程的环境中,所以开发人员根本不需要对于synchronized 的额外开销,所以在jdk1.5之后提供一个新的类StringBuilder ,这个类不是线程安全的也不是同步的,但是其使用更加方便而且在单线程环境中更加快速

性能测试

下面通过代码进行测试当创建动态的字符数组时String、StringBuffer、StringBuilder 三者需要的时间对比,测试代码如下:

public class Test {
 public static void main(String[] args) {
  new Test().constructDynamicString();
 }
 public void constructDynamicString()
 {
  long startTime = System.currentTimeMillis();
  String s = "test";
  //StringBuffer s = new StringBuffer("test");
  //StringBuilder s = new StringBuilder("test");
  for(int i=0; i<100000; i++)
  {
s += "concat";
//s.append("concat");
  }

  long endTime = System.currentTimeMillis();

  System.out.println("Concat time ====== " + (endTime - startTime) + "ms");
 }
}

结果如下:

String创建时间: 43144ms
StringBuffer创建时间: 14ms
StringBuilder创建时间: 14ms

第一次测试结果都是14ms,应该是数字较小,循环1000000次,统计结果

StringBuffer: Concat time ====== 80ms
StringBuilder: Concat time ====== 43ms

通过以上测试可以看出,在创建动态字符串过程中,使用String需要的时间最久,而使用StringBuilder时间最短,而且创建的次数越多这个性能越明显。

总结

通过以上的分析,那么在实际使用中我们怎么选择呢?

1、如果创建静态的字符串而且在程序中是不变的,那么选择String

2、如果是创建动态字符串,并且是在多线程中使用,那么用StringBuffer

3、其他的都使用StringBuilder,并且大多数情况下都是使用StringBuilder

相关栏目:

用户点评