今天谈下字符串。
众所周知,字符串操作是计算机编程中最常见的操作,我们无时无刻不在和字符串打交道,因此了解字符串的一些行为对编程有巨大的好处。
一、不可变类.
首先我们从Java的可变类与不可变类开始。那么什么是可变类,什么是不可变类呢?
顾名思义,可变类指的是你可以改变该类的实例的内容,而不可变类即你不可以改变该类的实例的内容。
如:int i = 1; 我们可以改变整形变量i的内容,如使i = 2;
而如果有一个字符串,如String s = "Hello,world!"。其实,我们看似可以进行改变字符串内容的行为,如s = "Hello,again"。然而事实上我们知道,s其实为一个String类型的引用上诉看似改变其内容的行为事实上是再创建了一个叫做"Hello,again"的新字符串,然后将String类型引用s从"Hello,world!"上重新指向了该新字符串,并非是改变了字符串的内容,然后没有引用指向的字符串"Hello,world!"由Java垃圾处理机制处理。
在Java中,String类型属于不可变类,其对象是不可变的。其实当你查看Java源代码时就会发现,对于String类中的每一个看似修改其内容改的方法,实际上都是再创建了一个新的String对象,然后包含修改后的字符串内容。
如:下面是String类中连接字符串的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);
}
可以看到连接字符串的操作实际上也是再创建了一个新的字符串,在包含修改后的内容。
在Java中的可变类有如全部的基本类型,不可变类有如String类,基本类型的包装类等。
以上是关于字符串的一些基本内部原理。
二、关于字符串的一些操作的性能测试
下面进行了对于字符串的+号连接操作,concat方法连接操作,StringBuffer的append操作测试:
<span style="white-space:pre"> </span>String s1 = "abc";
String s2 = "def";
long start = System.currentTimeMillis();
for(int i = 0; i < 100000; i++){
s1 += s2;
}
long end = System.currentTimeMillis();
long result = end - start;
System.out.println("+号操作时间:"+result);
s1 = "abc";
start = System.currentTimeMillis();
for(int i = 0; i < 100000; i++){
s1.concat(s2);
}
end = System.currentTimeMillis();
result = end - start;
System.out.println("concat号操作时间:"+result);
StringBuffer str = new StringBuffer("abc");
start = System.currentTimeMillis();
for(int i = 0; i < 100000; i++){
str.append("def");
}
str.toString();
end = System.currentTimeMillis();
result = end - start;
System.out.println("StringBuffer append操作时间:"+result);
得出结果为:
+号操作时间:11587
concat号操作时间:15
StringBuffer append操作时间:8
concat号操作时间:15
StringBuffer append操作时间:8
可以看到不同的方法拥有不同性能。
之前提到过String为不可变类,故其一些改变看似改变内容的方法操作实际上是创建了新的String类。而对于字符串连接操作,其内部实现也许使用的是列表也许使用了链表,由于各自采用算法的时间,空间复杂度不同,所以导致了性能差异。
不同的性能在实现应用复杂的功能时可能会带来一定影响。
以上便是在学习字符串时的一些了解和分享,若有不足,错误之处,望能给予指出批评。