请告诉我一个实时情景来比较 String
,StringBuffer
和 StringBuilder
?
请告诉我一个实时情景来比较 String
,StringBuffer
和 StringBuilder
?
可变性的区别:
String
是不可变的,如果你试图改变它们的值,会创建另一个对象,而StringBuffer
和StringBuilder
是可变的,因此它们可以改变它们的值。
线程安全的区别:
StringBuffer
和StringBuilder
的区别在于StringBuffer
是线程安全的。因此,当应用程序只需要在单个线程中运行时,最好使用StringBuilder
。 StringBuilder
比StringBuffer
更高效。
应用场景:
String
对象是不可变的。StringBuilder
就足够了。StringBuffer
,因为StringBuffer
是同步的,可以提供线程安全性。String
类型;从一个String
中获取新字符序列可能会带来无法接受的性能损失,无论是在CPU时间还是内存方面(获取子字符串是CPU效率高的方法,因为数据不会被复制,但这意味着可能仍然分配了大量的数据)。StringBuilder
类型。StringBuffer
类型,使用情况与StringBuilder
相同。参见示例此处。
基础知识:
String
是一个不可变的类,它不能被更改。
StringBuilder
是一个可变的类,可以添加、替换或删除字符,并最终转换为 String
。
StringBuffer
是 StringBuilder
的原始同步版本。
在只有单个线程访问对象的所有情况下,应优先选择 StringBuilder
。
详细信息:
还要注意,StringBuilder/Buffer
并不是魔法,它们只是使用数组作为支持对象,每当数组满时就必须重新分配。一定要最初创建足够大的 StringBuilder/Buffer
对象,以避免每次调用 .append()
时都需要不断地重新调整大小。
重新调整大小可能会变得非常恶化。它基本上将支持数组的大小每次扩展时增加到当前大小的两倍。当 StringBuilder/Buffer
类开始变得庞大时,这可能会导致大量未使用的 RAM 被分配。
String x = "A" + "B";
在幕后使用了一个StringBuilder
。因此,在简单情况下,声明自己的StringBuilder
没有任何好处。但是,如果您正在构建大型的String
对象,比如小于4k,则声明StringBuilder sb = StringBuilder(4096);
比连接或使用默认构造函数要高效得多,该构造函数仅有16个字符。如果您的String
将小于10k,则使用构造函数初始化为10k以确保安全。但是,如果它被初始化为10k,然后您写入超过10k的1个字符,它将被重新分配并复制到20k数组中。因此,高初始化比低初始化更好。StringBuilder/Buffer
时真正想避免的。 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);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
如果你不小心得到了一个你没有创建并且无法控制构造函数的StringBuilder/Buffer
实例,有一种方法可以避免退化的重新分配和复制行为。使用所需大小调用.ensureCapacity()
以确保你的结果String
适合。
其他选择:
顺便提一下,如果你正在进行非常繁重的String
构建和操作,有一种更注重性能的替代方案叫做Ropes。
ArrayList<String>
并添加计数器来跟踪每个.append()
和其他列表变异操作上的字符数,然后重写.toString()
以创建所需大小的StringBuilder
,循环遍历列表并构建输出,甚至可以将该StringBuilder
作为实例变量并“缓存”.toString()
的结果,并且只有在发生更改时才需要重新生成它。String.format()
,编译器可以对其进行优化,使其更好。String x = "A" + "B";
真的会编译成 StringBuilder 吗?为什么不直接编译成 String x = "AB";
呢?如果组件在编译时已知,它应该只使用 String 类型而不是 StringBuilder。 - Matt Greer您的意思是拼接字符串吗?
现实世界中的例子:您想从许多其他字符串中创建一个新字符串。
例如,发送消息:
String
String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I'm " + user.age + "yrs. old too"
可变字符串
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()
或者String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as fuzzy lollipop points out.
StringBuffer
(语法与 StringBuilder
完全相同,但效果不同)
关于
StringBuffer
与 StringBuilder
前者是同步的,后者不是。
因此,如果您在单个线程中多次调用它(这在90%的情况下是如此),StringBuilder
将运行快得多,因为它不会停下来检查是否拥有线程锁。
因此,建议使用 StringBuilder
(除非当然您有超过一个线程同时访问它,这是很少见的)
String
连接(使用 + 运算符)可能通过编译器优化为在底层使用 StringBuilder
,所以不再需要担心,在Java早期,这是所有人都说应该尽量避免的事情,因为每个连接都创建了一个新的字符串对象。现代编译器不再这样做,但仍然最好使用 StringBuilder
以防您使用“旧”的编译器。
编辑
只是为了好奇的人,这就是编译器为这个类所做的。
class StringConcatenation {
int x;
String literal = "Value is" + x;
String builder = new StringBuilder().append("Value is").append(x).toString();
}
使用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
}
第5-27行是给名为"literal"的字符串使用的。
第31-53行是给名为"builder"的字符串使用的。
没有区别,两个字符串完全执行相同的代码。
StringBuilder
在赋值右侧进行字符串连接不是一个好的编程实践。良好的实现将在后台使用StringBuilder
,正如您所说的那样。此外,您的例子"a" + "b"
将被编译为单个文字"ab"
,但如果您使用StringBuilder
则会导致两次无用的append()
调用。 - Mark Peters"a"+"b"
,而是想表达一下什么是字符串连接,所以我将其改为了显式的形式。你没有说的是,为什么这样做不是一个好习惯。这正是(现代)编译器所做的。@fuzzy,我同意,特别是当你知道最终字符串的大小(大约)时。 - OscarRyz字符串
String类
表示字符序列。在Java程序中,所有的字符串字面值(例如"abc"
)都是该类的实例。
一旦创建了字符串对象,它们就是不可变的,我们无法更改它们。(字符串是常量)
If a String is created using constructor or method then those strings will be stored in Heap Memory as well as SringConstantPool
. But before saving in pool it invokes intern()
method to check object availability with same content in pool using equals method. If String-copy is available in the Pool then returns the reference. Otherwise, String object is added to the pool and returns the reference.
+
), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method.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);
}
String literals are stored in StringConstantPool
.
String onlyPool = "Yash";
StringBuilder和StringBuffer是可变的字符序列。这意味着您可以更改这些对象的值。StringBuffer具有与StringBuilder相同的方法,但是StringBuffer中的每个方法都已同步,因此它是线程安全的。
StringBuffer and StringBuilder data can only be created using new operator. So, they get stored in Heap memory.
Instances of StringBuilder are not safe for use by multiple threads. If such synchronization is required then it is recommended that StringBuffer be used.
StringBuffer threadSafe = new StringBuffer("Yash");
threadSafe.append(".M");
threadSafe.toString();
StringBuilder nonSync = new StringBuilder("Yash");
nonSync.append(".M");
nonSync.toString();
StringBuffer and StringBuilder are having a Special methods like.,
replace(int start, int end, String str)
and reverse()
.
NOTE: StringBuffer and SringBuilder are mutable as they provides the implementation of
Appendable Interface
.
何时使用哪个。
If a you are not going to change the value every time then its better to Use String Class
. As part of Generics if you want to Sort Comparable<T>
or compare a values then go for 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);
If you are going to modify the value every time the go for StringBuilder which is faster than StringBuffer. If multiple threads are modifying the value the go for StringBuffer.
-------------------------------------------------------------- 字符串 StringBuffer StringBuilder -------------------------------------------------------------- 存储区 | 常量字符串池 堆 堆 可修改性 | 否(不可变) 是(可变) 是(可变) 线程安全性 | 是 是 否 性能 | 快 非常慢 快 --------------------------------------------------------------
StringBuffer
是线程安全的,而 StringBuilder
则不是。StringBuilder
可能会产生不确定的结果。StringBuilder
而不是StringBuffer
。根据API文档:StringBuilder
。通常应该优先使用StringBuilder
类,因为它支持所有相同的操作,但它速度更快,因为它不执行同步。StringBuffer
执行的同步几乎总是不必要的开销。个人而言,我认为StringBuffer
没有任何实际的应用场景。我什么时候需要通过操作字符序列在多个线程之间进行通信呢?这听起来一点也不有用,但也许我还没有看到光明 :)
但是为什么我们有两个用途相同的类呢?
原因是StringBuffer是线程安全的,而StringBuilder则不是。 StringBuilder是StringBuffer Api中的一个新类,在JDK5中引入,如果您在单线程环境中工作,则始终建议使用它,因为它更快速。
StringBuilder
中使用String
的所有方法吗? - roottraveller