在计算机程序设计中,字符串操作应该是最常见的行为之一,在 Web 系统的开发中更是如此。我觉得在Java中最应用最广泛的对字符串操作算是 String 类跟 StringBuffer 类了。
那么,到底 String 跟 StringBuffer 有什么区别跟联系呢?
首页,String 对象是不可变的。当我们修改一个 String 对象的值的时候,实际上都是重新创建了一个 String 对象,用以包含修改了以后的 String 类容。而最初的 String 对象则丝毫未动。
- public class TestString {
- public static void main(String[] args) {
- String s = "";
- s = "String";
- System.out.println("The string is : " + s);
- }
- }
public class TestString {
public static void main(String[] args) {
String s = "";
s = "String";
System.out.println("The string is : " + s);
}
}
在上例中,首先创建了一个 String 对象 s,初始值为 "" ,然后再给它赋值 "String",但是在内存中并不是简单的改变一下 s 引用指向的对象在内存中的数据池的值改变为 "String" 哦,实际上是在堆内存中重新开辟一个新的字符串空间,并赋值为 "String",然后复制一份原来 String 对象的引用,并指向这个新的字符串。
上面这段代码是对字符串的操作,看上去好像是没有问题的,但是需要说明的是这段代码的运行效率十分低下。我们可以通过 javap -c TestString 命令反编译这段代码,得到如下代码:
- Compiled from "TestString.java"
- public class TestString extends java.lang.Object{
- public TestString();
- Code:
- 0: aload_0
- 1: invokespecial #1; //Method java/lang/Object."<init>":()V
- 4: return
- public static void main(java.lang.String[]);
- Code:
- 0: ldc #2; //String
- 2: astore_1
- 3: ldc #3; //String String
- 5: astore_1
- 6: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
- 9: new #5; //class java/lang/StringBuilder
- 12: dup
- 13: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V
- 16: ldc #7; //String The string is :
- 18: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
- 21: aload_1
- 22: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
- 25: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
- 28: invokevirtual #10; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
- 31: return
- }
Compiled from "TestString.java"
public class TestString extends java.lang.Object{
public TestString();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String
2: astore_1
3: ldc #3; //String String
5: astore_1
6: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
9: new #5; //class java/lang/StringBuilder
12: dup
13: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V
16: ldc #7; //String The string is :
18: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: aload_1
22: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
28: invokevirtual #10; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
31: return
}
一段简单的代码,短短三条语句怎么变化了这么多呢?原因就在于 String 是不可变的!Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。而这个重载的处理可能因此误导很多人对 Java 中 String 的使用。
在上面的代码中可以发现 其实字符串串联是通过 StringBuilder
(或 StringBuffer
)类及其 append
方法实现的。JDK 帮助文档 写道:
StringBuilder
(or StringBuffer
) class and its append
method. String conversions are implemented through the method toString
, defined by Object
and inherited by all classes in Java. For additional information on string concatenation and conversion, see Gosling, Joy, and Steele, The Java Language Specification .
而 StringBuffer 是一个线程安全的可变字符序列。最主要的就是“可变”这两个字。这就意味着对 StringBuffer 的操作可以提升程序执行的效率。
StringBuffer 跟 StringBuilder 相比,都可以支持字符串的操作,但是在单线程中建议还是用 StringBuilder,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。 不过 StringBuilder 在多线程中是不安全的,所以在多线程的应用中最好还是用 StringBuffer。
如果你是要对字符串经常性的进行操作,StringBuffer 绝对比 String 要好,最后只需要调用 StringBuffer 的 toString 方法,就可以以一个最终的 String 形式保存了。
以上只是我对这两个类的一点点理解,希望各位有补充的尽量提出来,不胜感激。.....