str = str + word;//字符串连接
与 tempStringBuffer.append(word);
有什么差别??
(str为Sring对象,tempStringBuffer为StringBuffer对象,word字符串字面量)在连接后 str 与 word所在 存储空间是不是连续的??
是重新new了一个把str和word放进去还是别的什么?
与 tempStringBuffer.append(word);
有什么差别??
(str为Sring对象,tempStringBuffer为StringBuffer对象,word字符串字面量)在连接后 str 与 word所在 存储空间是不是连续的??
是重新new了一个把str和word放进去还是别的什么?
用String类创建的字符串是只读的。
当使用“+”运算符将一些字符加到某String对象上时,结果产生了新的对象,而不是原来String对象的一个修改值。
例:
String str1 = "abc",str2;
BufferString bfs = new BufferString("abc");
str2 = str1+"d";//now str1 is "abc" ;str2 is "abcd"
bfs.append("d");// now bfs is "abcd"
因为String 每次进行 + 操作,都会生成2个新的对象。浪费资源!影响效率特别是在面试的时候
说+ 是在编译前连接也就是说如String s = "abcd"+"efg"+"hrjk"编译后就直接生成"abcdefghrjk" 了 而StringBuffer的append是在运行期间追加的!
1 :+操作符会为字符串连接提供最佳的性能——当字符串是在编译期决定的时候。
2 :如果字符串在运行期决定,使用一个合适的初期容量值初始化的StringBuffer会为字符串连接提供最佳的性能
String str2 = "world";
String str3 = "str1";
String str1 = str1 + str2;//String 赋值实际上这个是NEW了一个新的对象了,str1变了
System.out.println(str3);//str3没有变,这是因为str3指向的地址还是最早的str1所在的地址
这里所做的内部操作,其实不是把str1的内容改变为原str1+str2的内容这么简单, 而把创建一个新的String, 内容为str1 + str2的内容,然后再把str1这个引用重新指向新创建的String, 而str3还指向最早的str1地址,并且内容还是"hello".而如果是StringBuffer的话,则直接更改str1的内容,而不是先创建一个新的StringBuffer.
StringBuffer b1=new StringBuffer("hello");
StringBuffer b2=b1;
b2.append("world");//StringBuffer赋值,操作b2还是那个对象
System.out.println(b1);String对象是不可变对象,一旦创建之后就不能再被改变,StringBuffer对象则是可变对象,可变对象则可以在创建之后被改变.为获得更佳的性能你需要根据实际情况小心谨慎地选择到底使用这两者中的某一个。String 是一种非常常用的数据类型,但由于 String 是不可变对象,在进行 String 的相关操作的时候会产生许多临时的 String 对象。
而 StringBuffer 在操作上是在一个缓冲中进行的,性能当然优越得多。
不过,一般做为简单的字符串传递和其它操作,只不要改变字符串内容的操作,用 String 效率会高一些。
所以结论是,JVM会内在地为字符串字面量维护一些唯一的 String对象,程序员不需要为字符串字面量而发愁,但是可能会被一些通过 new关键字创建的String对象而困扰,不过他们可以使用intern ()方法来避免在堆内存上创建重复的String对象来改善Java的运行性能。
同一个字符串对象被重复地创建是不必要的,String.intern ()方法可以避免这种情况。String.intern()方法检查字符串对象的存在性,如果需要的字符串对象已经存在,那么它会将引用指向已经存在的字符串对象而不是重新创建一个。StringTest2.java
package com.performance.string;
// This class shows the use of intern() method to improve performance
public class StringTest2 {
public static void main(String[] args){
// create String references like s1,s2,s3...so on..
String variables[] = new String[50000];
for( int i=0;i<variables.length;i++){
variables[i] = "s"+i;
}
// create String literals
long startTime0 = System.currentTimeMillis();
for(int i=0;i<variables.length;i++){
variables[i] = "hello";
}
long endTime0 = System.currentTimeMillis();
System.out.println("Time taken for creation of String literals : "
+ (endTime0 - startTime0) + " milli seconds" );
// create String objects using 'new' keyword
long startTime1 = System.currentTimeMillis();
for(int i=0;i<variables.length;i++){
variables[i] = new String("hello");
}
long endTime1 = System.currentTimeMillis();
System.out.println("Time taken for creation of String objects with 'new' key word : "
+ (endTime1 - startTime1)+" milli seconds");
// intern String objects with intern() method
long startTime2 = System.currentTimeMillis();
for(int i=0;i<variables.length;i++){
variables[i] = new String("hello");
variables[i] = variables[i].intern();
}
long endTime2 = System.currentTimeMillis();
System.out.println("Time taken for creation of String objects with intern(): "
+ (endTime2 - startTime2)+" milli seconds");
}
}
这是上面那段代码的输出结果:
Time taken for creation of String literals : 0 milli seconds
Time taken for creation of String objects with 'new' key word : 160 milli seconds
Time taken for creation of String objects with intern(): 60 milli seconds可以使用+操作符或者String.concat()或者StringBuffer.append()等办法来连接多个字符串,那一种办法具有最佳的性能呢?
如何作出选择取决于两种情景,第一种情景是需要连接的字符串是在编译期决定的还是在运行期决定的,第二种情景是你使用的是 StringBuffer还是String。通常StringBuffer.append()方法会优于+操作符或 String.concat()方法,但是在一些特定的情况下这个假想是不成立的。
请看下面的StringTest3.java代码和输出结果。package com.performance.string;
/** This class shows the time taken by string concatenation at compile time and run time.*/
public class StringTest3 {
public static void main(String[] args){
//Test the String Concatination
long startTime = System.currentTimeMillis();
for(int i=0;i<5000;i++){
String result = "This is"+ "testing the"+ "difference"+ "between"+
"String"+ "and"+ "StringBuffer";
}
long endTime = System.currentTimeMillis();
System.out.println("Time taken for string concatenation using + operator : "
+ (endTime - startTime)+ " milli seconds");
//Test the StringBuffer Concatination
long startTime1 = System.currentTimeMillis();
for(int i=0;i<5000;i++){
StringBuffer result = new StringBuffer();
result.append("This is");
result.append("testing the");
result.append("difference");
result.append("between");
result.append("String");
result.append("and");
result.append("StringBuffer");
}
long endTime1 = System.currentTimeMillis();
System.out.println("Time taken for String concatenation using StringBuffer : "
+ (endTime1 - startTime1)+ " milli seconds");
}
}
这是上面的代码的输出结果:
Time taken for String concatenation using + operator : 0 milli seconds
Time taken for String concatenation using StringBuffer : 50 milli seconds
很有趣地,+操作符居然比StringBuffer.append()方法要快,为什么呢?
这里编译器的优化起了关键作用,编译器像下面举例的那样简单地在编译期连接多个字符串。它使用编译期决定取代运行期决定,在你使用new关键字来创建String对象的时候也是如此。
编译前:
String result = "This is"+"testing the"+"difference"+"between"+"String"+"and"+"StringBuffer";
编译后:
String result = "This is testing the difference between String and StringBuffer";这里String对象在编译期就决定了,而StringBuffer对象是在运行期决定的。运行期决定需要额外的开销当字符串的值无法预先知道的时候,编译期决定作用于字符串的值可以预先知道的时候,下面是一个例子。
编译前:
public String getString(String str1,String str2) {
return str1+str2;
}
编译后:
return new StringBuffer().append(str1).append(str2).toString();
运行期决定需要更多的时间来运行。
2) 第二种情景:运行期决定
看看下面的代码你会发现与情景一相反的结果——连接多个字符串的时候StringBuffer要比String快。
StringTest4.java
package com.performance.string;
/** This class shows the time taken by string concatenation
using + operator and StringBuffer */
public class StringTest4 {
public static void main(String[] args){
//Test the String Concatenation using + operator
long startTime = System.currentTimeMillis();
String result = "hello";
for(int i=0;i<1500;i++){
result += "hello";
}
long endTime = System.currentTimeMillis();
System.out.println("Time taken for string concatenation using + operator : "
+ (endTime - startTime)+ " milli seconds");
//Test the String Concatenation using StringBuffer
long startTime1 = System.currentTimeMillis();
StringBuffer result1 = new StringBuffer("hello");
for(int i=0;i<1500;i++){
result1.append("hello");
}
long endTime1 = System.currentTimeMillis();
System.out.println("Time taken for string concatenation using StringBuffer : "
+ (endTime1 - startTime1)+ " milli seconds");
}
}
这是上面的代码的输出结果:
Time taken for string concatenation using + operator : 280 milli seconds
Time taken for String concatenation using StringBuffer : 0 milli seconds
看得出StringBuffer.append()方法要比+操作符要快得多,原因是两者都是在运行期决定字符串对象。
关键点
1. 无论何时只要可能的话使用字符串字面量来常见字符串而不是使用new关键字来创建字符串。
2. 无论何时当你要使用new关键字来创建很多内容重复的字符串的话,请使用String.intern()方法。
3. +操作符会为字符串连接提供最佳的性能——当字符串是在编译期决定的时候。
4. 如果字符串在运行期决定,使用一个合适的初期容量值初始化的StringBuffer会为字符串连接提供最佳的性能。
编译时,实际上是翻译为:
StringBuffer sb = new StringBuffer();
sb.append("abc");
sb.append(str);
....
最后调用sb.toString()因此,如果只是一个串联,那么直接用+号就可以了,性能没有差别,代码更简单。
但是如果在循环中使用+号来串联,因为每次串联都会被翻译为上面的代码,导致创建了很多StringBuffer对象实例,所以会慢得多。