操作字符串是计算机程序设计中最常见的行为,尤其是在web开发中。所以大家一定要掌握java中常见的字符串操作。并且要深入学习String类,因为String是一个比较特别类。它有很多特性需要注意。
首先大家应该知道字符串本质是就是一个char类型的数组,例如 "Hello" 这个字符串就是由 'H'、'e'、'l'、'l'、'o' 这五个字符组成。在java中把这字符数组当成String的一个实例。可以对其进行各种操作。
一些常规的操作我们就不多说了,大家可以自己去看java api,我们在这儿说一下String的特性。和使用过程中的一下问题
不可变性
在学习使用java的时候,有一个非常重要的概念,那就是一旦一个String对象被创建,它就是不变的(immutable)。String类中每一个看起来是修改String值的方法。实际上都会创建一个新的String对象 看下面的代码
/**
* 说明String的不可变性
* Created by wanghailong on 17/3/15.
*/
public class Immutable {
public static void main(String[] args) {
String q = "fighting";
System.out.println(q);
String qq = q.toUpperCase();
System.out.println(q);
System.out.println(qq);
}
}
我们看上面这个例子,我们可以看到对String值的操作,不会对原始值有任何影响,调用toUpperCase()方法后,其实是会创建一个新的对象。这其实也是我们想要的。我们也不希望调用之后改变原来的值,要不然这个代码的可读性和维护成本就非常高了。
说到这儿,我们可以引起另外一个概念,就是在java执行的时候,会维护一个String池,在创建一个字符串的时候,会先在String池中查找是否有相同的String内容。如果有就直接返回。这会导致他们指向的是同一个字符串数组
String str1 = "flyweight";
String str2 = "flyweight";
System.out.println(str1 == str2);
如上图所示
那么在这儿我问个问题:
String str1 = new String("caterpillar");
String str2 = new String("caterpillar");
System.out.println(str1 == str2);
这段代码执行会返回 true 吗?答案不会,为什么呢?原因是‘==’是用来比较变量是否指向同一个对象。她不是用来比较对象的内容的,这一点大家要注意。两个对象的内容是否相等,只能通过equals()来个比较。这个我们就不在这儿展开讲了。大家在做相等比较的时候,尽量还是使用equals()来比较
StringBuilder
在说StringBuilder的之前,我们先说一下“+”操作符在String中的意义,"+"和"+="对于String是特殊意义的,事实上,用于字符串操作的"+"和"+="是唯一被重载过的操作符。
public class StringAdd {
public static void main(String[] args) {
String mango = "test";
String s = "a"+"b"+"c"+mango;
System.out.println(s);
}
}
这个代码的执行逻辑是这样的,先生成包含"a"的String对象,"a"+"b"又生成一个包含"ab"的对象,以此类推。
这种执行方式逻辑上是没有问题的。但是为了生成最终的字符串,这段代码执行过程中会生成一大堆需要垃圾回收的中间对象。
在J2SE 5.0开始提供java.lang.StringBuilder类,使用这个类所产生的对象预设会有16个字节的长度,你也可以自行指定初始长度,如果附加的字符超出可容纳的长度,则StringBuilder对象会自动增加长度以容纳被附加的字符,如果有频繁作字串附加的需求,使用StringBuilder会让程序的效率大大提升,来写个简单的测试程序就可以知道性能差距有多大。
public class AppendStringTest {
public static void main(String[] args) {
String text = "test";
long beginTime = System.currentTimeMillis();
for(int i = 0; i < 10000; i++){
text = text + i;
}
long endTime = System.currentTimeMillis();
System.out.println("执行时间:" + (endTime - beginTime));
StringBuilder builder = new StringBuilder("");
beginTime = System.currentTimeMillis();
for(int i = 0; i < 10000; i++){
builder.append(i);
}
endTime = System.currentTimeMillis();
System.out.println("执行时间:" + (endTime - beginTime));
}
}
//结果
执行时间:456
执行时间:3
StringBuilder是J2SE5.0引入的,在这之前java用的是StringBuffer,StringBuffer是线程安全的。因此开销会大一些,不推荐使用