Jav*_*ser 206 java oop string stringbuilder
请告诉我一个实时的情况来比较String
,StringBuffer
和StringBuilder
?
bak*_*kal 369
可变性差异:
String
是不可变的,如果你试图改变它们的值,另一个对象被创建,StringBuffer
而且StringBuilder
是可变的,所以它们可以改变它们的值.
线程安全差异:
之间的区别StringBuffer
,并StringBuilder
是StringBuffer
是线程安全的.因此,当应用程序只需要在单个线程中运行时,最好使用它StringBuilder
.StringBuilder
效率比StringBuffer
.
情况:
String
对象是不可变的.StringBuilder
就足够了.StringBuffer
因为StringBuffer
是同步的,因此您具有线程安全性.Art*_*cto 47
String
,当一个不变的结构是合适的; 从获得一个新的字符序列String
可以携带不可接受的性能损失,无论是在CPU时间或存储器(获取子是CPU有效的,因为该数据是不可复制的,但这意味着数据的一个潜在的更大的量可以保持已分配).StringBuilder
需要创建可变字符序列时使用,通常是将多个字符序列连接在一起.StringBuffer
你会使用相同的情况下StringBuilder
,但是当底层字符串的变化必须是同步的(因为有几个线程读取/ modifyind字符串缓冲区).在这里查看示例.
小智 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()
在构建固定格式化输出时也不要忘记,这可以由编译器优化,因为它们使它更好.
你的意思是,连接?
真实世界的例子: 你想要从许多其他人创建一个新的字符串.
例如发送消息:
串
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完全一样,效果不同)
关于
StringBuffer
与 StringBuilder
前者是同步的,后来则不是.
所以,如果你调用它几次在一个单独的线程(这是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
疗法没有区别,完全一样的代码为两个字符串执行.
串
该String class
代表字符串.Java程序中的所有字符串文字,例如作为此类的"abc"
实例实现.
字符串对象一旦创建就不可变,我们无法更改.(字符串是常量)
如果使用构造函数或方法创建String,那么这些字符串将存储在堆内存中以及SringConstantPool
.但是在保存在池中之前,它调用intern()
方法来使用equals方法在池中检查具有相同内容的对象可用性.如果池中有String-copy,则返回引用.否则,将String对象添加到池中并返回引用.
+
)提供特殊支持,并为其他对象转换为字符串.字符串连接是通过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)
StringBuilder和StringBuffer是可变的字符序列.这意味着可以改变这些对象的值.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.
---------------------------------------------------------------------------------- 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 ----------------------------------------------------------------------------------
归档时间: |
|
查看次数: |
163539 次 |
最近记录: |