有关String中字符串拼接
1.字符串常量拼接
String str1="Hello"+" world";
String str2="Hello world";
System.out.println(str3==str4);//true
上面是字符串常量拼接的例子:在编译时,JVM编译器对字符串做了优化,str1就被优化成"Hello world",str1和str2指向字符串常量池同一个字符串变量,所以结果为true。
2.字符串常量+字符串变量、字符串变量之间的拼接
String str5="Hello";
String str6=" world";
Stirng str7="Hello world";
String str8=str5+" world";
System.out.println(str7==str8);//false
String通过+号来拼接字符串的时候,如果有字符串变量参与,实际上底层会转成通过StringBuilder的append()方法来实现,大致过程如下:
StringBuilder sb=new StringBuilder();
sb.append(str5);
sb.append(" world");
str8=sb.toString();
StirngBuilder的toString()方法底层new了一个String对象,所以str8在堆内存中重新开辟了新空间,而str7指向常量池,所以str7==str8为false。
变量字符串拼接和常量字符串拼接结果是不一样的。因为变量字符串拼接是会先开辟空间,然后再拼接。
基本概念
字符串不变性:String是常量,是Java中一个不可变的类,其对象一旦被创建就不能再被改变,换句话说,每一个看起来被修改的值,实际上都是创造了一个全新的String对象 。
使用+拼接字符串的实现原理:
String对象后面跟着一个 “+” 时,不管 “+” 后面的是什么数据(可能不是Strig对象),都会转换为字符串。转换时是通过调用该对象的toString()方法。string + 其实是由 stringbuilder 的 append()方法 完成的。编译器使用 append() 方法追加后用 toString() 转换成 String字符串(自动转换,不需要重写toString()方法),也就说 str +=”b” 等同于
str = new StringBuilder(str).append(“b”). toString() ;
它变慢的关键原因就在于new StringBuilder()和toString(),这里可是创建了10W个StringBuilder对象,而且每次还需要将其转换成 String 。
同时,当使用 “+” 拼接字符串时,会生成新的String对象,而不是向原有的String对象追加内容,故 效率较低。
String wechat = “Hollis”;
String introduce = “每日更新Java相关技术文章”;
String hollis = wechat + “,” + introduce;
反编译后的内容如下,反编译工具为jad。
String wechat = “Hollis”; String introduce = “每日更新Java相关技术文章”;
String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString();
通过查看反编译以后的代码,我们可以发现,原来字符串常量在拼接过程中,是将String转成了StringBuilder后,使用其append方法进行处理的。那么也就是说,Java中的+对字符串的拼接,其实现原理是使用StringBuilder.append。
concat是如何实现的
当两个量都为String类型且值不为null时,可以用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);
}
这段代码首先创建了一个字符数组,长度是已有字符串和待拼接字符串的长度之和,再把两个字符串的值复制到新的字符数组中,并使用这个字符数组创建一个新的String对象并返回。通过源码我们也可以看到,经过concat方法,其实是new了一个新的String,这也就呼应到前面我们说的字符串的不变性问题上了。
append 方式
StringBuilder 类和 StringBuffer 类使用 append() 方法追加字符串,向 原有对象 追加而 不 是 新建 对象,toString()方法返回String类对象。
StringBuilder 和 StringBuffe r的主要区别:StringBuffer 是线程 安全 的, StringBuilder效率 更高。
( 关于字符串,Java中除了定义了一个可以用来定义字符串常量的String类以外,还提供了可以用来定义字符串变量的StringBuffer类,它的对象是可以扩充和修改的。使用StringBuffer可以方便的对字符串进行拼接)
对于三者 运行效率而言,append() 速度最快,concat() 次之,+ 最慢。但是当 “+” 拼接时 ,连接的是常量时,编译器在编译期就完成了这个运算,效率高。
**对于三者使用的总结:
** 1.如果要操作少量的数据且在字符串 不 经常 变化 的场景中用 : String+
2.单线程操作字符串缓冲区下 频繁 操作 大 量数据 :StringBuilder
3.多线程操作字符串缓冲区下 频繁 操作 大 量数据 :StringBuffer