String,StringBuffer和StringBuilder

Jav*_*ser 206 java oop string stringbuilder

请告诉我一个实时的情况来比较String,StringBufferStringBuilder

bak*_*kal 369

可变性差异:

String不可变的,如果你试图改变它们的值,另一个对象被创建,StringBuffer而且StringBuilder可变的,所以它们可以改变它们的值.

线程安全差异:

之间的区别StringBuffer,并StringBuilderStringBuffer是线程安全的.因此,当应用程序只需要在单个线程中运行时,最好使用它StringBuilder.StringBuilder效率比StringBuffer.

情况:

  • 如果您的字符串不会更改,请使用String类,因为String对象是不可变的.
  • 如果您的字符串可以更改(例如:字符串构造中的大量逻辑和操作)并且只能从单个线程访问,则使用a StringBuilder就足够了.
  • 如果您的字符串可以更改,并且将从多个线程访问,请使用StringBuffer因为StringBuffer是同步的,因此您具有线程安全性.

  • 此外,使用String进行逻辑操作相当慢,并且根本不建议,因为JVM将String转换为字节码中的StringBuffer.浪费了很多开销,从String转换为StringBuffer,然后再转换回String. (16认同)
  • 所以在`Strings`中,当我们改变值时,会创建另一个对象.旧的对象引用是否无效,以便它可能被`GC`垃圾收集或甚至是垃圾收集? (2认同)

Art*_*cto 47

  • 您可以使用String,当一个不变的结构是合适的; 从获得一个新的字符序列String可以携带不可接受的性能损失,无论是在CPU时间或存储器(获取子是CPU有效的,因为该数据是不可复制的,但这意味着数据的一个潜在的更大的量可以保持已分配).
  • StringBuilder需要创建可变字符序列时使用,通常是将多个字符序列连接在一起.
  • 您可以使用StringBuffer你会使用相同的情况下StringBuilder,但是当底层字符串的变化必须是同步的(因为有几个线程读取/ modifyind字符串缓冲区).

在这里查看示例.

  • 它简洁但不完整,它错过了使用StringBuilder/Buffer的基本原因,即减少或消除常规String连接行为的重新分配和数组副本. (2认同)

小智 28

基础:

String是一个不可变的类,它不能改变. StringBuilder是一个可变类,可以附加到,替换或删除字符,最终转换为a String StringBuffer是原始的同步版本StringBuilder

StringBuilder在所有只有一个线程访问对象的情况下,您应该更喜欢.

细节:

还要注意,StringBuilder/Buffers这不是魔术,它们只是使用一个数组作为后备对象,并且当数组变满时必须重新分配数组.确保并且StringBuilder/Buffer最初创建足够大的对象,而不必在每次.append()调用时不断调整大小.

重新调整大小会变得很堕落.每次需要扩展时,它基本上将后备阵列的大小重新调整为当前大小的2倍.这可能导致分配大量RAM,并在StringBuilder/Buffer类开始变大时不使用.

在Java中String x = "A" + "B";使用StringBuilder幕后.因此,对于简单的情况,声明自己没有任何好处.但是如果你构建的String对象很大,比如小于4k,那么声明StringBuilder sb = StringBuilder(4096);比连接或使用只有16个字符的默认构造函数更有效.如果你的String小于10k,那么使用构造函数将其初始化为10k是安全的.但是如果它初始化为10k然后你写1个字符超过10k,它将被重新分配并复制到20k数组.所以初始化高比低.

在自动重新大小的情况下,在第17个字符处,后备阵列被重新分配并复制到32个字符,在第33个字符处再次发生这种情况,您可以重新分配并将阵列复制到64个字符.你可以看到它如何退化为大量的重新分配和副本,这是你真正试图避免StringBuilder/Buffer首先使用的.

这是来自AbstractStringBuilder的JDK 6源代码

   void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
        if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {
        newCapacity = minimumCapacity;
    }
        value = Arrays.copyOf(value, newCapacity);
    }
Run Code Online (Sandbox Code Playgroud)

一个最佳实践是初始化StringBuilder/Buffer比你认为你需要的稍微大一点,如果你不知道它String会有多大,但你可以猜到.一个比你需要的内存略多的分配将比许多重新分配和副本更好.

还要注意StringBuilder/Buffer用a 初始化a String只会分配String + 16个字符的大小,这在大多数情况下只会启动你试图避免的简并重新分配和复制周期.以下内容直接来自Java 6源代码.

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
    }
Run Code Online (Sandbox Code Playgroud)

如果你偶然得到一个StringBuilder/Buffer你没有创建的实例,并且无法控制被调用的构造函数,那么有一种方法可以避免退化的重新分配和复制行为..ensureCapacity()使用您想要的尺寸拨打电话,以确保您的结果String符合.

替代方案:

正如笔记所说,如果你正在进行非常沉重的 String构建和操作,那么有一种更加注重性能的替代方案叫做Ropes.

另一种方法是StringList通过子类创建实现ArrayList<String>,并添加计数器来跟踪.append()列表的每个和其他变异操作上的字符数,然后重写.toString()以创建StringBuilder所需的确切大小并循环遍历列表并构建在输出中,您甚至可以将其StringBuilder作为实例变量并"缓存"结果,.toString()并且只有在发生变化时才需要重新生成它.

String.format()在构建固定格式化输出时也不要忘记,这可以由编译器优化,因为它们使它更好.


Osc*_*Ryz 9

你的意思是,连接?

真实世界的例子: 你想要从许多其他人创建一个新的字符串.

例如发送消息:

String s = "Dear " + user.name + "<br>" + 
" I saw your profile and got interested in you.<br>" +
" I'm  " + user.age + "yrs. old too"
Run Code Online (Sandbox Code Playgroud)

StringBuilder的

String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" ) 
          .append(" I saw your profile and got interested in you.<br>") 
          .append(" I'm  " ).append( user.age ).append( "yrs. old too")
          .toString()
Run Code Online (Sandbox Code Playgroud)

要么

String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as  fuzzy lollipop points out.
Run Code Online (Sandbox Code Playgroud)

StringBuffer(语法与StringBuilder完全一样,效果不同)

关于

StringBufferStringBuilder

前者是同步的,后来则不是.

所以,如果你调用它几次在一个单独的线程(这是90%的病例), StringBuilder将运行快,因为它不会停下来看看它是否拥有线程锁.

因此,建议使用StringBuilder(除非您当然有多个线程同时访问它,这很少见)

String连接(使用+运算符)可以由编译器优化以在StringBuilder下面使用,因此,不再需要担心,在Java的老年时代,这是每个人都应该不惜一切代价避免的事情,因为每个连接创建了一个新的String对象.现代编译器不再这样做了,但是StringBuilder如果你使用"旧"编译器,那么使用它仍然是一个好习惯.

编辑

只是为了好奇的人,这就是编译器为这个类做的事情:

class StringConcatenation {
    int x;
    String literal = "Value is" + x;
    String builder = new StringBuilder().append("Value is").append(x).toString();
}
Run Code Online (Sandbox Code Playgroud)

javap -c StringConcatenation

Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;

java.lang.String literal;

java.lang.String builder;

StringConcatenation();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   new #2; //class java/lang/StringBuilder
   8:   dup
   9:   invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   12:  ldc #4; //String Value is
   14:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   17:  aload_0
   18:  getfield    #6; //Field x:I
   21:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   24:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   27:  putfield    #9; //Field literal:Ljava/lang/String;
   30:  aload_0
   31:  new #2; //class java/lang/StringBuilder
   34:  dup
   35:  invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   38:  ldc #4; //String Value is
   40:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   43:  aload_0
   44:  getfield    #6; //Field x:I
   47:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   50:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   53:  putfield    #10; //Field builder:Ljava/lang/String;
   56:  return

}
Run Code Online (Sandbox Code Playgroud)

编号为5 - 27的行用于名为"literal"的字符串

编号为31-53的行用于名为"builder"的String

疗法没有区别,完全一样的代码为两个字符串执行.

  • 这是一个非常糟糕的例子.使用"Dear"初始化StringBuilder意味着第一个.append()将导致重新分配和复制.完全否定你试图通过"正常"连接获得的任何效率.一个更好的例子是使用初始大小创建它,该大小将保存最终String的全部内容. (2认同)

Yas*_*ash 8

字符串系列

String class代表字符串.Java程序中的所有字符串文字,例如作为此类的"abc"实例实现.

字符串对象一旦创建就不可变,我们无法更改.(字符串是常量)

  • 如果使用构造函数或方法创建String,那么这些字符串将存储在堆内存中以及SringConstantPool.但是在保存在池中之前,它调用intern()方法来使用equals方法在池中检查具有相同内容的对象可用性.如果池中有String-copy,则返回引用.否则,将String对象添加到池中并返回引用.

    • Java语言为字符串连接运算符(+)提供特殊支持,并为其他对象转换为字符串.字符串连接是通过StringBuilder(或StringBuffer)类及其append方法实现的.

    String heapSCP = new String("Yash");
    heapSCP.concat(".");
    heapSCP = heapSCP + "M";
    heapSCP = heapSCP + 777;
    
    // For Example: String Source Code 
    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 字符串文字存储在StringConstantPool.

    String onlyPool = "Yash";
    
    Run Code Online (Sandbox Code Playgroud)

StringBuilderStringBuffer是可变的字符序列.这意味着可以改变这些对象的值.StringBuffer与StringBuilder具有相同的方法,但StringBuffer中的每个方法都是同步的,因此它是线程安全的.

  • StringBuffer和StringBuilder数据只能使用new运算符创建.因此,它们存储在堆内存中.

  • StringBuilder的实例不适合多线程使用.如果需要这样的同步,则建议使用StringBuffer.

    StringBuffer threadSafe = new StringBuffer("Yash");
    threadSafe.append(".M");
    threadSafe.toString();
    
    StringBuilder nonSync = new StringBuilder("Yash");
    nonSync.append(".M");
    nonSync.toString();
    
    Run Code Online (Sandbox Code Playgroud)
  • StringBuffer和StringBuilder有一个特殊的方法,如., replace(int start, int end, String str)reverse().

    注意:StringBuffer和SringBuilder是可变的,因为它们提供了实现Appendable Interface.


何时使用哪一个.

  • 如果您不打算每次更改该值,那么最好使用它String Class.作为泛型的一部分,如果您想要对Comparable<T>值进行排序或比较,那么请选择String Class.

    //ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
    Set<StringBuffer> set = new TreeSet<StringBuffer>();
    set.add( threadSafe );
    System.out.println("Set : "+ set);
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果要在每次运行StringBuilder时修改该值,那么比StringBuffer快.如果多个线程正在修改值,则转到StringBuffer.


Abh*_*ity 7

----------------------------------------------------------------------------------
                  String                    StringBuffer         StringBuilder
----------------------------------------------------------------------------------                 
Storage Area | Constant String Pool         Heap                   Heap 
Modifiable   |  No (immutable)              Yes( mutable )         Yes( mutable )
Thread Safe  |      Yes                     Yes                     No
 Performance |     Fast                 Very slow                  Fast
----------------------------------------------------------------------------------