1、字符串的拼接(以java语言为例)
1.1、主要方法:
String+=String;
String.concat(String);
StringBuffer.append(String);
StringBuilder.append(String);
1.2、效率分析
测试代码:
public class StringTest {
public static void main(String[] args) {
StringTest st = new StringTest();
String str = new String("");
String add = new String("0");
System.out.println(st.normalConcat(str, add, 10000));
System.out.println(st.stringConcat(str, add, 10000000));
System.out.println(st.bufferConcat(str, add, 10000000));
System.out.println(st.builderConcat(str, add, 10000000));
}
/**String+=String**/
public long normalConcat(String source,String add,int times){
long start=System.currentTimeMillis();
for(int i=0;i<times;i++){
source+=add;
}
long end = System.currentTimeMillis();
return end-start;
}
/**String.concat(String)**/
public long stringConcat(String source,String add,int times){
long start=System.currentTimeMillis();
for(int i=0;i<times;i++){
source.concat(add);
}
long end = System.currentTimeMillis();
return end-start;
}
/**StringBuffer.append(String)**/
public long bufferConcat(String source,String add,int times){
long start=System.currentTimeMillis();
StringBuffer sb = new StringBuffer(source);
for(int i=0;i<times;i++){
sb.append(add);
}
source=sb.toString();
long end = System.currentTimeMillis();
return end-start;
}
/**StringBuilder.append(String)**/
public long builderConcat(String source,String add,int times){
long start=System.currentTimeMillis();
StringBuilder sb = new StringBuilder(source);
for(int i=0;i<times;i++){
sb.append(add);
}
source=sb.toString();
long end = System.currentTimeMillis();
return end-start;
}
}
注释三种,每次只执行一种拼接方法获得数据得如下表格:
每次单字符拼接
每次十字符拼接
效率:“+=”<concat<buffer<builder
从表格数据看出“+=”与concat的效率在同一数量级而buffer、builder效率远超其上;
1.3、原理分析:
contrast:按需扩充(仅足以容纳完成拼接后的字符串),每次拼接都要新开内存,copy数据,效率低;
builder:指数级扩充,有容量(最大能存储字符数)设定,每次到达容量时,开 辟出两倍的内存,只在扩容时copy数据,效率高,空间开销大;
buffer:与builder基本相同,多了线程同步,有额外的时间开销,效率较高,比 builder低;
“+=”:反编译得知:JVM会隐式创建StringBuilder,在调用append(String) 拼接效率应与builder在同 一数量级。但重复的“+=”,意味着重复的创建 StringBuilder,使其效率降至contrast的数量级。
1.4、拼接方案选择
简单拼接、单次拼接,常用“+=”或是contrast,相比其它两种使用要简单;
大量拼接,无线程同步要求,使用StringBuilder;
大量拼接,需要线程同步,使用StringBuffer;
一定量的拼接,时间效率要求低,空间效率要求高,使用contrast;
2、字符串的比较
public class Test {
public static void main(String[] args) {
String str1 ="123";
String str2 = new String("123");
String str3 ="123";
System.out.println(str1==str2);
System.out.println(str1.equals(str2));
System.out.println(str1==str3);
}
}
其结果为:
2.1、查询得知java中两个对象用==比较的是地址;
2.2、查看equals方法源码:
地址是否相同,即“==”;
是否为String实例,否返回false;
是String实例,逐字符比对,有不同返回false,否则返回true;
所以,equals方法比的是值;
2.3、解释:
由于JVM的底层优化机制,内存中存在一个可以共享的字符串池。以“123”的形式建立字符串时,会先检索池中是否已存在相同的字符串,如果有,则返回它的地址,否则新建,并添入池中;
而显式的new关键字,则带有明确的新建字符串的要求,不会添入字符串池;
故第一个结果为false,第三个结果为true;
这样提高了内存的使用效率,避免相同字符串的重复建立,同时由于String类中的数据是final的,没有数据紊乱的安全隐患。
类似的还有Integer;
若直接以Integer i = 0;形式建立,在-128~127范围内,“==”返回true即:地址相同;
JVM事先在一片字段中存入Integer对象-128~127(该范围是高频使用范围),须要使用时,直接返回其引用,避免重复建立,提高效率。