[TOC]

概述

我们经常遇到的一个面试题:请简要说一下String、StringBuffer、StringBuilder区别?

我们都知道StringBuffer、StringBuilder,但是这两个的用法都差不多,真是傻傻分不清楚。到底有什么区别呢?所以我们结合String类来分析一下这三者的区别。
下面,我们先看一个表格

类型 值是否可变 线程安全
String 不可变 安全(线程同步)
StringBuilder 可变 不安全(线程不同步)
StringBuffer 可变 安全(线程同步)

首先,我们来分析一下String类.

1
2
3
4
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
......
}

通过查看源码得知:String类是一个final类。所以可以很清楚的知道,final类是改变不了的,所以,如果我们用String来操作字符串的时候,一旦我们字符串的值改变,就会在内存创建多一个空间来保存新的字符串,可想而知:如果我们需要操作字符串,修改字符串的内容。用String是多么低效率的事啊!所以当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。

与String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

接着,我们来看StringBuilder类。

1
2
3
4
5
6
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
......
}

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

最后,我们来看看StringBuffer类。

们从源码也可以看出,StringBuffer的绝大多数方法都是synchronized方法,也就是线程安全的。因为StringBuffer要维持同步锁,这肯定要消耗部分资源。由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{

@Override
public synchronized int length() {
return count;
}
......
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
}
1
2
3
4
5
6
7
8
9
public class Test{
public static void main(String args[]){
StringBuffer sBuffer = new StringBuffer("菜鸟教程官网:");
sBuffer.append("www");
sBuffer.append(".runoob");
sBuffer.append(".com");
System.out.println(sBuffer);
}
}

StringBuffer 方法
以下是 StringBuffer 类支持的主要方法:

1
2
3
4
5
6
7
8
9
10
//将指定的字符串追加到此字符序列。
public StringBuffer append(String s)
//将此字符序列用其反转形式取代。
public StringBuffer reverse()
//移除此序列的子字符串中的字符。
public delete(int start, int end)
//将 int 参数的字符串表示形式插入此序列中。
public insert(int offset, int i)
//使用给定 String 中的字符替换此序列的子字符串中的字符。
replace(int start, int end, String str)

下面的列表里的方法和 String 类的方法类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1   int capacity()
返回当前容量。
2 char charAt(int index)
返回此序列中指定索引处的 char 值。
3 void ensureCapacity(int minimumCapacity)
确保容量至少等于指定的最小值。
4 void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
将字符从此序列复制到目标字符数组 dst。
5 int indexOf(String str)
返回第一次出现的指定子字符串在该字符串中的索引。
6 int indexOf(String str, int fromIndex)
从指定的索引处开始,返回第一次出现的指定子字符串在该字符串中的索引。
7 int lastIndexOf(String str)
返回最右边出现的指定子字符串在此字符串中的索引。
8 int lastIndexOf(String str, int fromIndex)
返回 String 对象中子字符串最后出现的位置。
9 int length()
返回长度(字符数)。
10 void setCharAt(int index, char ch)
将给定索引处的字符设置为 ch。
11 void setLength(int newLength)
设置字符序列的长度。
12 CharSequence subSequence(int start, int end)
返回一个新的字符序列,该字符序列是此序列的子序列。
13 String substring(int start)
返回一个新的 String,它包含此字符序列当前所包含的字符子序列。
14 String substring(int start, int end)
返回一个新的 String,它包含此序列当前所包含的字符子序列。
15 String toString()
返回此序列中数据的字符串表示形式。

所以,下面我们来回答这个面试题目:

题目一:String类能被继承吗,为什么?

首先,答案是不能。因为首先String是final关键字来修饰的,final类不能被继承。所以当我们需要。所以,如果我们用String来操作字符串的时候,一旦我们字符串的值改变,就会在内存创建多一个空间来保存新的字符串。

题目二:String,Stringbuffer,StringBuilder的区别。
答案如上