不可变字符串类String
字符串的创建有两种方式:
1. String s1 = new String("123456");
2. String s2 = "123456";
s1使用new来新建一个String对象,放在堆中
不管字符串缓冲池中有没有匹配的字符串常量,都会new一个字符串对象。
s2使用等号来创建一个String对象
首先jvm会查看字符串缓冲池中有没有值"123456"的对象,
如果有,就将这个字符串对象的地址传给s2;
如果没有,将在字符串缓冲池中新建一个字符串对象,将新的对象地址传给s2。
下面我们来比较两种不同方式建立的字符串,加深一下字符串创建的理解
String s1 = new String("123456");
String s2 = "123456";
if(s1 == s2)
System.out.println(s1 == s2);
else
System.out.println(s1 != s2);
输出结果:true
根据两种创建方式,很容易理解这两个字符串变量指向同一个对象的地址,
所以s1和s2完全相等。
那么如果使用new建立两个的字符串,结果必然为false
为什么说String类的字符串不可变?
我们可以查看JDK,很容易发现所有的String类的方法中没有改变字符串值的方法,字符串对象存在堆中,对象的值为字符串常量放在字符串缓冲区中,因为字符串常量不可改变,故字符串不可改变。
举个栗子
String类中的replace方法也是先将原字符串复制一份,在新的字符串对象中
将指定字符替换
查看String类源码,可以看到String类为 final 类,字符串的值放在final数组value[]中,所以我们把字符串的值叫字符串常量,因为常量不可变。
可变字符串类StringBuffer和StringBuilder
StringBuffer和StringBuilder有一个共同点,他们都可以拼接字符串(通过append方法),并能改变字符串的值(有JDK文档就可以看出来)。
二者的区别在于StringBuffer是多线程,线程安全;StringBuilder是单线程,线程不安全,如果频繁使用字符串拼接,建议使用StringBuilder。
虽然String可以通过重载运算符来进行字符串拼接,但是这只适合少量的,如果出现大量字符串拼接,还是使用StringBuilder。
拓展一下
StringBuilder字符串拼接和String字符串拼接
String s1 = "hello";
String s2 = "world";
System.out.println(s1+s2);
这时候使用 + 来拼接字符串很方便。
当出现很多字符串时,我们就能看到字符串拼接的不足。
举个栗子
public static void main(String[] args) {
String s = "oh,";
String[] ss = new String[] {"he", "llo", "wo", "rl", "d!"};
for(int i = 0; i < ss.length; i++){
s += ss[i];
}
System.out.println(s);
}//输出:oh,helloworld!
我们利用javap反编译一下这个循环(javap -c Main)
在每次循环中我们都会new一个StringBuilder对象,
使用append方法将字符串拼接后使用toString方法转换为字符串给字符串s
既然使用String直接拼接用到了StringBuilder,我们还不如直接新建一个StringBuilder对象。
public static void main(String[] args) {
String s = "oh,";
StringBuilder cs = new StringBuilder(s);
String[] ss = new String[] {"he", "llo", "wo", "rl", "d!"};
for(int i = 0; i < ss.length; i++){
cs.append(ss[i]);
}
s = cs.toString();
System.out.println(s);
}//输出:oh,helloworld!
很显然,我们发现循环中的代码减少了,那么也提升了拼接的效率
这就是我们要使用StringBuilder拼接的原因。
总结
其实String利用加法拼接字符串是将‘+’和‘+=’重载了,类似于C++中的运算符重载,但是Java中只允许重载这两个运算符,重载就是利用了StringBuilder的append方法,所以,遇到大量的拼接,我们还是要多使用StringBuilder。
String和StringBuffer及StringBuilder的区别同时也是面试题,不光我们要知道原理,还要能举出实例来论证。