62

Java中的String和StringBuffer有什么区别?

字符串有最大大小吗?

4

15 回答 15

75

String用于操作无法更改(只读和不可变)的字符串。

StringBuffer用于表示可以修改的字符。

性能方面,StringBuffer执行连接时更快。这是因为当您连接 a 时String,您每次都在(内部)创建一个新对象,因为String它是不可变的。

您也可以使用StringBuilderwhich is similar to ,StringBuffer但它不同步。其中任何一个的最大大小为Integer.MAX_VALUE(2 31 - 1 = 2,147,483,647) 或最大堆大小除以 2(请参阅Java 字符串可以包含多少个字符?)。更多信息在这里

于 2010-03-13T17:28:26.840 回答
34

AString是不可变的,即当它被创建时,它永远不会改变。

A StringBuffer(或其非同步表亲StringBuilder)在您需要逐段构造字符串时使用,而无需在此过程中构造大量小Strings 的性能开销。

两者的最大长度都是 Integer.MAX_VALUE,因为它们在内部存储为数组,而 Java 数组只有一个int用于长度的伪字段。

Strings 和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");
    }
}
于 2010-03-13T17:28:57.640 回答
24
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
于 2013-03-22T06:54:16.457 回答
10

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%,可能是一个列表)。

于 2011-03-04T16:58:24.520 回答
4

API:

一个线程安全的、可变的字符序列。字符串缓冲区类似于字符串,但可以修改。在任何时候它都包含一些特定的字符序列,但是序列的长度和内容可以通过某些方法调用来改变。

于 2011-03-04T16:50:25.550 回答
2

StringBuffer 用于从多个字符串创建单个字符串,例如,当您想在循环中附加部分字符串时。

当您只有一个线程访问 StringBuffer 时,您应该使用 StringBuilder 而不是 StringBuffer,因为 StringBuilder 不同步,因此速度更快。

AFAIK 作为一种语言,Java 中的字符串大小没有上限,但 JVM 可能有上限。

于 2010-03-13T17:27:03.447 回答
2

我发现 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 对象的成本非常高。

总之,上面的两行代码导致创建了三个对象:

  1. 位置 0 的 String 对象
  2. 位置 10 的 StringBuffer 对象
  3. 位置 26 的 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 的转换。

于 2010-11-23T06:55:49.793 回答
2

通过在任何追加操作之后打印 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
于 2016-06-23T06:02:18.613 回答
1

AString是一个不可变的字符数组。

AStringBuffer是一个可变字符数组。String通常在完成变​​异后转换回。

由于两者都是数组,因此两者的最大大小等于整数的最大大小,即 2^31-1(请参阅JavaDoc,也请查看两者的 JavaDocStringStringBuffer)。这是因为.length数组的参数是原始的int。(参见数组)。

于 2010-03-13T17:29:23.257 回答
1

每当您要进行大量字符串连接时,首选AStringBuffer或其更年轻和更快的兄弟StringBuilder

string += newString;

或等效地

string = string + newString;

因为上述构造每次都会隐式创建字符串,这将是一个巨大的性能下降。A StringBuffer/StringBuilder在引擎盖下最好与动态可扩展的List<Character>.

于 2010-03-13T17:29:49.937 回答
1

String 是不可变的,这意味着当您对 String 执行操作时,您实际上是在创建一个全新的 String。

StringBuffer是可变的,您可以附加到它,也可以将其长度重置为 0。

实际上,出于性能原因,编译器似乎在字符串连接期间使用 StringBuffer 。

于 2011-03-04T16:50:41.860 回答
1
String is immutable. 

为什么?在这里检查。

StringBuffer is not. It is thread safe. 

进一步的问题,例如何时使用 which 和其他概念可以在此之后弄清楚。

希望这可以帮助。

于 2013-07-25T06:44:01.500 回答
1

虽然我知道这不是主要的区别因素,但我今天注意到 StringBuffer(和 StringBuilder)提供了一些有趣的方法,而 String 没有。

  • 逆转()
  • setCharAt()
于 2014-11-20T03:14:56.717 回答
1

区别是

  1. 只有在String类中+运算符才被重载。我们可以使用+运算符连接两个 String 对象,但在StringBuffer的情况下我们不能。
  2. 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
    
  3. 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
    
  4. 我们可以使用或不使用new运算符创建 String 对象,但 StringBuffer 对象只能使用new运算符创建。

  5. String 是不可变的,但 StringBuffer 是可变的。
  6. StringBuffer 是同步的,而 String 不是。
  7. StringBuffer 有一个内置的reverse()方法,但 String 没有它。
于 2017-01-17T13:28:55.970 回答
0

性能方面 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

于 2016-06-11T10:21:34.067 回答