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

时间:2010-03-13 17:25:47

标签: java string stringbuilder stringbuffer

Java中String和StringBuffer有什么区别?

String的最大大小是什么?

15 个答案:

答案 0 :(得分:75)

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

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

性能方面,StringBuffer在执行连接时速度更快。这是因为当你连接String时,每次String都是不可变的,你就会在内部创建一个新对象。

除了未同步之外,您还可以使用与StringBuilder类似的StringBuffer。其中任何一个的最大大小为Integer.MAX_VALUE(2 31 - 1 = 2,147,483,647)或最大堆大小除以2(请参阅How many characters can a Java String have?)。 更多信息here

答案 1 :(得分:34)

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

当您需要逐个构造字符串时,使用StringBuffer(或其非同步的表兄StringBuilder),而不会构建大量小String s的性能开销方式。

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

多个连接的StringStringBuffer之间的性能提升非常重要。如果您运行以下测试代码,您将看到差异。在我使用Java 6的古老笔记本电脑上,我得到了这些结果:

Concat with String took: 1781ms
Concat with StringBuffer took: 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");
    }
}

答案 2 :(得分:23)

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

答案 3 :(得分:10)

String是一个不可变的类。这意味着一旦你像这样实例化一个字符串的实例:

String str1 = "hello";

内存中的对象无法更改。相反,您将不得不创建一个新实例,复制旧String并附加其他任何内容,如下例所示:

String str1 = "hello";
str1 = str1 + " world!";

真正发生的事情是我们没有更新现有的str1对象......我们正在重新分配新内存,复制“hello”数据并附加“world!”到最后,然后将str1引用设置为指向此新内存。所以它真的看起来更像这样:

String str1 = "hello";
String str2 = str1 + " world!";
str1 = str2;

因此,如果特别以递归的方式进行复制,那么“复制+粘贴并在内存中移动内容”过程可能会非常昂贵。

当你处于不得不反复使用StringBuilder的情况时。它是可变的,并且可以将字符串附加到当前字符串的末尾,因为它返回[正在增长的数组](如果这是实际数据结构,则不是100%,可以是列表)。

答案 4 :(得分:4)

来自API:

  

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

答案 5 :(得分:2)

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

当你只有一个Thread访问StringBuffer时,你应该使用StringBuilder而不是StringBuffer,因为StringBuilder不是同步的,因此更快。

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

答案 6 :(得分:2)

我找到了Reggie Hutcherso比较性能String vs 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对象的第一个示例更昂贵。 / p>

+运算符看似无辜,但生成的代码会产生一些惊喜。使用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对象
  4. 现在,让我们看一下使用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连接明显快于字符串连接。显然,StringBuffers应尽可能用于此类操作。如果需要String类的功能,请考虑使用StringBuffer进行连接,然后执行一次到String的转换。

答案 7 :(得分:2)

通过在任何追加操作也证明之后打印String / StringBuffer对象的哈希码,每次使用新值而不是使用相同的String对象时,会在内部重新创建String对象。

?g_id

输出: 它打印对象值及其哈希码

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());
    }

 }

}

答案 8 :(得分:1)

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

StringBuffer是一个可变字符数组。完成变异时经常转换回String

由于两者都是一个数组,因此两者的最大大小等于整数的最大大小,即2 ^ 31-1(参见JavaDoc,同时检查两个{{1}的JavaDoc }和String)。这是因为数组的StringBuffer参数是原始.length。 (见Arrays)。

答案 9 :(得分:1)

StringBuffer或更年轻,更快的兄弟StringBuilder,无论何时进行大量的字符串连接,都是首选

string += newString;

或等效

string = string + newString;

因为上述构造每次都会隐式创建 new 字符串,这将是一个巨大的性能和下降。最好与StringBuffer / StringBuilder进行比较,以便与动态可扩展的List<Character>进行比较。

答案 10 :(得分:1)

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

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

实际上,编译器似乎在字符串连接for performance reasons期间使用StringBuffer。

答案 11 :(得分:1)

String is immutable. 

为什么呢?检查here

StringBuffer is not. It is thread safe. 

可以在this之后找出更多问题,例如何时使用哪些概念和其他概念。

希望这有帮助。

答案 12 :(得分:1)

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

  • 反向()
  • setCharAt()

答案 13 :(得分:1)

差异是

  1. 仅在字符串 + 运算符中重载。我们可以使用 + 运算符连接两个String对象,但是对于 StringBuffer ,我们可以&#t; t。
  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. 字符串类同时可序列化以及可比较,但 StringBuffer 序列化

    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对象,但只能使用 new 运算符创建StringBuffer对象。

  5. String是不可变的,但StringBuffer是可变的。
  6. StringBuffer已同步,而String ain&#t; t。
  7. StringBuffer有一个内置的 reverse()方法,但String没有它。

答案 14 :(得分:0)

性能明智的StringBuffer比String好多了;因为无论何时在String Object上应用连接,都会在每个连接上创建新的String对象。

主要规则:字符串是不可变的(不可修改)和StringBuffer是可变的(可修改的)

以下是编程实验,您可以获得性能差异

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(); 
  }
 }

String的输出在我的机器中    14800

StringBuffer的输出在我的机器中   14