Java中的String和StringBuffer有什么区别?
字符串有最大大小吗?
String
用于操作无法更改(只读和不可变)的字符串。
StringBuffer
用于表示可以修改的字符。
性能方面,StringBuffer
执行连接时更快。这是因为当您连接 a 时String
,您每次都在(内部)创建一个新对象,因为String
它是不可变的。
您也可以使用StringBuilder
which is similar to ,StringBuffer
但它不同步。其中任何一个的最大大小为Integer.MAX_VALUE
(2 31 - 1 = 2,147,483,647) 或最大堆大小除以 2(请参阅Java 字符串可以包含多少个字符?)。更多信息在这里。
AString
是不可变的,即当它被创建时,它永远不会改变。
A StringBuffer
(或其非同步表亲StringBuilder
)在您需要逐段构造字符串时使用,而无需在此过程中构造大量小String
s 的性能开销。
两者的最大长度都是 Integer.MAX_VALUE,因为它们在内部存储为数组,而 Java 数组只有一个int
用于长度的伪字段。
String
s 和s之间的多重连接的性能提升StringBuffer
是相当显着的。如果您运行以下测试代码,您将看到差异。在我使用 Java 6 的老式笔记本电脑上,我得到了以下结果:
Concat 与 String 耗时:1781ms Concat 与 StringBuffer 耗时:0ms
public class Concat
{
public static String concatWithString()
{
String t = "Cat";
for (int i=0; i<10000; i++)
{
t = t + "Dog";
}
return t;
}
public static String concatWithStringBuffer()
{
StringBuffer sb = new StringBuffer("Cat");
for (int i=0; i<10000; i++)
{
sb.append("Dog");
}
return sb.toString();
}
public static void main(String[] args)
{
long start = System.currentTimeMillis();
concatWithString();
System.out.println("Concat with String took: " + (System.currentTimeMillis() - start) + "ms");
start = System.currentTimeMillis();
concatWithStringBuffer();
System.out.println("Concat with StringBuffer took: " + (System.currentTimeMillis() - start) + "ms");
}
}
String StringBuffer
Immutable Mutable
String s=new String("karthik"); StringBuffer sb=new StringBuffer("karthik")
s.concat("reddy"); sb.append("reddy");
System.out.println(s); System.out.println(sb);
O/P:karthik O/P:karthikreddy
--->once we created a String object ---->once we created a StringBuffer object
we can't perform any changes in the existing we can perform any changes in the existing
object.If we are trying to perform any object.It is nothing but mutablity of
changes with those changes a new object of a StrongBuffer object
will be created.It is nothing but Immutability
of a String object
Use String--->If you require immutabilty
Use StringBuffer---->If you require mutable + threadsafety
Use StringBuilder--->If you require mutable + with out threadsafety
String s=new String("karthik");
--->here 2 objects will be created one is heap and the other is in stringconstantpool(scp) and s is always pointing to heap object
String s="karthik";
--->In this case only one object will be created in scp and s is always pointing to that object only
String 是一个不可变的类。这意味着一旦你像这样实例化一个字符串的实例:
String str1 = "hello";
内存中的对象无法更改。相反,您必须创建一个新实例,复制旧字符串并附加任何其他内容,如本例所示:
String str1 = "hello";
str1 = str1 + " world!";
真正发生的事情是我们没有更新现有的 str1 对象......我们一起重新分配新内存,复制“hello”数据并附加“world!” 到最后,然后将 str1 引用设置为指向这个新内存。所以它在引擎盖下看起来更像这样:
String str1 = "hello";
String str2 = str1 + " world!";
str1 = str2;
因此,如果以递归方式重复完成,这种“复制+粘贴并在内存中移动”过程可能会非常昂贵。
当您处于不得不一遍又一遍地做事的情况下,请使用 StringBuilder。它是可变的,并且可以将字符串附加到当前字符串的末尾,因为它由一个 [增长的数组] 返回(如果那是实际的数据结构,则不是 100%,可能是一个列表)。
从API:
一个线程安全的、可变的字符序列。字符串缓冲区类似于字符串,但可以修改。在任何时候它都包含一些特定的字符序列,但是序列的长度和内容可以通过某些方法调用来改变。
StringBuffer 用于从多个字符串创建单个字符串,例如,当您想在循环中附加部分字符串时。
当您只有一个线程访问 StringBuffer 时,您应该使用 StringBuilder 而不是 StringBuffer,因为 StringBuilder 不同步,因此速度更快。
AFAIK 作为一种语言,Java 中的字符串大小没有上限,但 JVM 可能有上限。
我发现 Reggie Hutcherso 比较性能 String 与 StringBuffer 的有趣答案 来源:http ://www.javaworld.com/javaworld/jw-03-2000/jw-0324-javaperf.html
Java 提供了StringBuffer 和String 类,String 类用于操作不能更改的字符串。简单地说,String 类型的对象是只读且不可变的。StringBuffer 类用于表示可以修改的字符。
这两个类之间的显着性能差异是 StringBuffer 在执行简单连接时比 String 快。在字符串操作代码中,字符串通常被连接起来。使用 String 类,连接通常按如下方式执行:
String str = new String ("Stanford ");
str += "Lost!!";
如果要使用 StringBuffer 执行相同的连接,则需要如下所示的代码:
StringBuffer str = new StringBuffer ("Stanford ");
str.append("Lost!!");
开发人员通常认为上面的第一个示例效率更高,因为他们认为使用 append 方法进行连接的第二个示例比使用 + 运算符连接两个 String 对象的第一个示例成本更高。
+ 运算符看起来很无辜,但生成的代码会产生一些惊喜。使用 StringBuffer 进行连接实际上可以生成比使用 String 快得多的代码。要发现为什么会这样,我们必须检查两个示例中生成的字节码。使用 String 的示例的字节码如下所示:
0 new #7 <Class java.lang.String>
3 dup
4 ldc #2 <String "Stanford ">
6 invokespecial #12 <Method java.lang.String(java.lang.String)>
9 astore_1
10 new #8 <Class java.lang.StringBuffer>
13 dup
14 aload_1
15 invokestatic #23 <Method java.lang.String valueOf(java.lang.Object)>
18 invokespecial #13 <Method java.lang.StringBuffer(java.lang.String)>
21 ldc #1 <String "Lost!!">
23 invokevirtual #15 <Method java.lang.StringBuffer append(java.lang.String)>
26 invokevirtual #22 <Method java.lang.String toString()>
29 astore_1
位置 0 到 9 的字节码针对第一行代码执行,即:
String str = new String("Stanford ");
然后,执行位置 10 到 29 的字节码进行连接:
str += "Lost!!";
事情在这里变得有趣。为连接生成的字节码创建一个 StringBuffer 对象,然后调用它的 append 方法:临时 StringBuffer 对象在位置 10 创建,它的 append 方法在位置 23 处调用。由于 String 类是不可变的,因此必须使用 StringBuffer级联。
对 StringBuffer 对象执行连接后,必须将其转换回 String。这是通过调用位置 26 处的 toString 方法来完成的。该方法从临时 StringBuffer 对象创建一个新的 String 对象。这个临时 StringBuffer 对象的创建及其随后转换回 String 对象的成本非常高。
总之,上面的两行代码导致创建了三个对象:
现在,让我们看看使用 StringBuffer 为示例生成的字节码:
0 new #8 <Class java.lang.StringBuffer>
3 dup
4 ldc #2 <String "Stanford ">
6 invokespecial #13 <Method java.lang.StringBuffer(java.lang.String)>
9 astore_1
10 aload_1
11 ldc #1 <String "Lost!!">
13 invokevirtual #15 <Method java.lang.StringBuffer append(java.lang.String)>
16 pop
位置 0 到 9 的字节码在第一行代码中执行:
StringBuffer str = new StringBuffer("Stanford ");
然后执行位置 10 到 16 的字节码进行连接:
str.append("Lost!!");
请注意,与第一个示例中的情况一样,此代码调用 StringBuffer 对象的 append 方法。然而,与第一个示例不同的是,不需要创建临时 StringBuffer 并将其转换为 String 对象。此代码仅在位置 0 处创建一个对象,即 StringBuffer。
总之,StringBuffer 连接明显快于 String 连接。显然,StringBuffers 应该尽可能用于这种类型的操作。如果需要 String 类的功能,请考虑使用 StringBuffer 进行连接,然后执行一次到 String 的转换。
通过在任何追加操作之后打印 String/StringBuffer 对象的哈希码也证明,String 对象每次都在内部使用新值重新创建,而不是使用相同的 String 对象。
public class MutableImmutable {
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("String is immutable");
String s = "test";
System.out.println(s+"::"+s.hashCode());
for (int i = 0; i < 10; i++) {
s += "tre";
System.out.println(s+"::"+s.hashCode());
}
System.out.println("String Buffer is mutable");
StringBuffer strBuf = new StringBuffer("test");
System.out.println(strBuf+"::"+strBuf.hashCode());
for (int i = 0; i < 10; i++) {
strBuf.append("tre");
System.out.println(strBuf+"::"+strBuf.hashCode());
}
}
}
输出:它打印对象值及其哈希码
String is immutable
test::3556498
testtre::-1422435371
testtretre::-1624680014
testtretretre::-855723339
testtretretretre::2071992018
testtretretretretre::-555654763
testtretretretretretre::-706970638
testtretretretretretretre::1157458037
testtretretretretretretretre::1835043090
testtretretretretretretretretre::1425065813
testtretretretretretretretretretre::-1615970766
String Buffer is mutable
test::28117098
testtre::28117098
testtretre::28117098
testtretretre::28117098
testtretretretre::28117098
testtretretretretre::28117098
testtretretretretretre::28117098
testtretretretretretretre::28117098
testtretretretretretretretre::28117098
testtretretretretretretretretre::28117098
testtretretretretretretretretretre::28117098
每当您要进行大量字符串连接时,首选AStringBuffer
或其更年轻和更快的兄弟StringBuilder
string += newString;
或等效地
string = string + newString;
因为上述构造每次都会隐式创建新字符串,这将是一个巨大的性能下降。A StringBuffer
/StringBuilder
在引擎盖下最好与动态可扩展的List<Character>
.
String 是不可变的,这意味着当您对 String 执行操作时,您实际上是在创建一个全新的 String。
StringBuffer是可变的,您可以附加到它,也可以将其长度重置为 0。
实际上,出于性能原因,编译器似乎在字符串连接期间使用 StringBuffer 。
String is immutable.
为什么?在这里检查。
StringBuffer is not. It is thread safe.
进一步的问题,例如何时使用 which 和其他概念可以在此之后弄清楚。
希望这可以帮助。
虽然我知道这不是主要的区别因素,但我今天注意到 StringBuffer(和 StringBuilder)提供了一些有趣的方法,而 String 没有。
区别是
String类重写了Object类的toString()、equals()、hashCode() ,但是StringBuffer只重写了toString()。
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.equals(s2)); // output true
StringBuffer sb1 = new StringBuffer("abc");
StringBuffer sb2 = new StringBuffer("abc");
System.out.println(sb1.equals(sb2)); // output false
String类既是Serializable又是Comparable,但StringBuffer只是Serializable。
Set<StringBuffer> set = new TreeSet<StringBuffer>();
set.add(sb1);
set.add(sb2);
System.out.println(set); // gives ClassCastException because there is no Comparison mechanism
我们可以使用或不使用new运算符创建 String 对象,但 StringBuffer 对象只能使用new运算符创建。
性能方面 StringBuffer 比 String 好得多;因为每当您在 String Object 上应用连接时,都会在每个连接上创建新的 String 对象。
主要规则:字符串是不可变的(不可修改的)和字符串缓冲区是可变的(可修改的)
这是您获得性能差异的程序化实验
public class Test {
public static int LOOP_ITERATION= 100000;
public static void stringTest(){
long startTime = System.currentTimeMillis();
String string = "This";
for(int i=0;i<LOOP_ITERATION;i++){
string = string+"Yasir";
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
public static void stringBufferTest(){
long startTime = System.currentTimeMillis();
StringBuffer stringBuffer = new StringBuffer("This");
for(int i=0;i<LOOP_ITERATION;i++){
stringBuffer.append("Yasir");
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
public static void main(String []args){
stringTest()
stringBufferTest();
}
}
字符串的输出在我的机器 14800中
StringBuffer 的输出在我的机器上 14