在 java中,字符串的拼接方式你肯定不陌生,但是有注意过他们的区别吗?
常用方法
使用+拼接
使用+拼接是我们比较常用的做法
String s="hello";
String s1="world";
String s2=s+","+s1;
这种方式,有一些人会认为这是操作符重载,其实不然,Java中是不支持操作符重载的!其实这是Java的语法糖!
concat方法拼接
String s = "hello";
String s1 = "world";
String s2 = s.concat(",").concat(s1);
StringBuffer & StringBuilder
StringBuffer sb=new StringBuffer("hello");
StringBuffer sb1=new StringBuffer("world");
StringBuffer sb2=sb.append(",").append(sb1);
StringBuilder sb=new StringBuilder("hello");
StringBuilder sb1=new StringBuilder("world");
StringBuilder sb2=sb.append(",").append(sb1);
原理
“ +” 的原理
对以下代码进行反编译
String s="hello";
String s1="world";
String s2=s+","+s1;
得到如下代码
String s="hello";
String s1="world";
String s2=(new StringBuilder()).append(s).append(",").append(s1).toString();
由此我们可以看出,使用“+”进行字符拼接,实际上是使用了StringBuilder的append方法将字符串拼接起来,然后返回一个新的字符串!
concat的原理
//concat的源码
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);
}
通过查看concat方法的源代码我们可以看出,concat对于字符串的拼接是将原字符串与拼接的字符串存入了一个新的字符数组中,然后产生一个新的字符串来实现的!
StringBuffer & StringBuilder 的append方法原理
StringBuilder与String相似,都定义了一个字符数组
char[] value;
但是StringBuilder与String不同的是 字符数组value并没有用final修饰,这就意味着Stringbuilder的value是可变的!
另外, StringBuilder字符数组中不一定所有位置都已经被使用,它有一个实例变量,表示数组中已经使用的字符 个数,定义如下:
int count;
我们查看append方法的源代码
// StringBuffer
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
//StringBuilder
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
可以看出,StringBuffer的append方法使用了synchronized修饰,所以它是线程安全的!
StringBuilder与StringBuffer都继承了AbstractStringBuilder这个类。查看其append源代码如下:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
// 判断是否需要扩容
ensureCapacityInternal(count + len);
// 将需要拼接的字符串放到字符数组中
str.getChars(0, len, value, count);
// 更新字符数组已用的数量
count += len;
return this;
}
效率比较
long begin = System.currentTimeMillis();
//这里是初始字符串定义
for (int i = 0; i < 50000; i++) {
//这里采用不通形式的字符串拼接方式
}
long end = System.currentTimeMillis();
System.out.println("cost:" + (end - begin));
测试结果
+cost:4990
StringBuilder cost:15
StringBuffer cost:16
concat cost:1650
结果分析
通过结果我们可以得出一下结论:
速度由大到小排列为:StringBuilder>StringBuffer>concat>"+"
1、StringBuffer比StringBuilder慢的原因是其加入了synchronized
2、“+”同样采用StringBuilder的append方法为什么效率会这么低呢?其实通过反编译后的代码我们不难看出来,使用“+”进行拼接会反复的进行 实例化的过程,花费了很多时间!
但是,在我们日常工作中还要强调的是:
1、如果不是在循环体中进行字符串拼接的话,直接使用+就好了。
2、如果在并发场景中进行字符串拼接的话,要使用 StringBuffer 来代替 StringBuilder。