String
在 Java 中定义一个变量为 string 类型如下:
// 定义变量 url 类型为字符串
String url = "www.baidu.com";
String字符串与数组有一个共同点,就是它们被初始化后,长度是不变的,并且内容也不变。如果要改变它的值,就会产生一个新的字符串:
String str = "Hello ";
str += "World!";
程序首先产生了str1字符串,并在内存中申请了一段空间。此时要追加新的字符串是不可能的,因为字符串被初始化后,长度是固定的。如果要改变它,只有放弃原来的空间,重新申请能够容纳“Hello World!”字符串的内存空间,然后将“Hello World!”字符串放到内存中。
实际上,String 是java.lang包下的一个类,按照标准的面向对象的语法,其格式应该为:
String stringName = new String("string content");
例如:
String url = new String("http://www.awen.me");
但是由于String特别常用,所以Java提供了一种简化的语法。
使用简化语法的另外一个原因是,按照标准的面向对象的语法,在内存使用上存在比较大的浪费。例如String str = new String(“abc”);实际上创建了两个String对象,一个是”abc”对象,存储在常量空间中,一个是使用new关键字为对象str申请的空间。
常用操作
下面是关于字符串的替换、切割、长度使用方法
String url = "www.baidu.com";
System.out.println(url.length()); //输出 13,无论是数字还是字母或汉字,每个字符的长度都是1
String str = "123456789";
System.out.println(str.charAt(0)); // 输出1,str 的索引 0 是1
String str1 = "www.awen.me";
String str2 = str1.replace("awen.me","google.com");
System.out.println(str2); //输出 www.google.com
String str3 = "www_awen_me";
String strArr[] = str3.split("_");
System.out.println(Arrays.toString(strArr));//输出 [www, awen, me]
StringBuffer
String 的值是不可变的,每次对String的操作都会生成新的String对象,不仅效率低,而且耗费大量内存空间。
StringBuffer类和String类一样,也用来表示字符串,但是StringBuffer的内部实现方式和String不同,在进行字符串处理时,不生成新的对象,在内存使用上要优于String。
StringBuffer 默认分配16字节长度的缓冲区,当字符串超过该大小时,会自动增加缓冲区长度,而不是生成新的对象。
/**
* String 的值是不可变的,每次对 String 的操作都会生成新的 String 对象,不仅效率低,而且还耗费大量的内存空间
*
* StringBuffer 和 String 类一样,也是用来表示字符串,但 StringBuffer 不生成新的对象,在内存使用上要优于 String
*/
StringBuffer str1 = new StringBuffer(); //分配16个字节长度的缓冲区
StringBuffer str2 = new StringBuffer(512); // 分配512个字节长度的缓冲区
// 在缓存区中存放了字符串,并且在后面预留了16个字节长度的缓冲区
StringBuffer str3 = new StringBuffer("www.awen.me");
/**
* StringBuffer类的主要方法
*/
StringBuffer str4 = new StringBuffer("abcd");
append() 方法
// append 方法
StringBuffer str5 = str4.append(true);
System.out.println(str4 == str5);//输出 true,注意这里是 str4 的内容变了,不是其地址变了。
String str6 = "adcd";
String str7 = str6 + "efg";
System.out.println(str6 == str7); // 输出 false,因为地址变了
/**字符串的”+“操作实际上也是先创建一个StringBuffer对象,然后调用append()方法将字符串片段拼接起来,最后调用toString()方法转换为字符串。
*
* 这样看来,String的连接操作就比StringBuffer多出了一些附加操作,效率上必然会打折扣。
*/
deleteCharAt() 和 delete()
deleteCharAt() 方法用来删除指定位置的字符,并将剩余的字符形成新的字符串。
StringBuffer str = new StringBuffer("sswsdeed");
str.deleteCharAt(3); // 删除索引为3的字符,即第三个 s,输出 sswdeed
System.out.println(str);
str.delete(1,4); //删除1-4之间的字符,即输出 seed
System.out.println(str);
insert()
insert() 用来在指定位置插入字符串,可以认为是append()的升级版。
StringBuffer str = new StringBuffer("sswsdeed");
str.deleteCharAt(3); // 删除索引为3的字符,即第三个 s,输出 sswdeed
System.out.println(str);
str.delete(1,4); //删除1-4之间的字符,即输出 seed
System.out.println(str);
str.insert(3,"xyz"); //输出 seexyzd
System.out.println(str);
setCharAt()
setCharAt() 方法用来修改指定位置的字符。
StringBuffer str = new StringBuffer("sswsdeed");
str.deleteCharAt(3); // 删除索引为3的字符,即第三个 s,输出 sswdeed
System.out.println(str);
str.delete(1,4); //删除1-4之间的字符,即输出 seed
System.out.println(str);
str.insert(3,"xyz"); //输出 seexyzd
System.out.println(str);
str.setCharAt(3,'z'); //输出 seezyzd
System.out.println(str);
String 和 StringBuffer 的效率对比
public static void main(String[] args) {
String fragment = "abcdefghijklmnopqrstuvwxyz";
int times = 10000;
// 测试 string 对象
long timeStart1 = System.currentTimeMillis();
String str1 = "";
for (int i = 0; i < times; i++) {
str1 +=fragment;
}
long timeEnd1 = System.currentTimeMillis();
System.out.println("String = ["+(timeEnd1 - timeStart1)+ "ms]");
// 通过StringBuffer
long timeStart2 = System.currentTimeMillis();
StringBuffer str2 = new StringBuffer();
for (int i = 0; i < times; i++) {
str2.append(fragment);
}
long timeEnd2 = System.currentTimeMillis();
System.out.println("StringBuffer= [" + (timeEnd2 - timeStart2) + "ms]");
}
结果:
StringBuilder类
StringBuilder类和StringBuffer类功能基本相似,方法也差不多,主要区别在于StringBuffer类的方法是多线程安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。
使用环境:
- 操作少量的数据使用 String;
- 单线程操作大量数据使用 StringBuilder;
- 多线程操作大量数据使用 StringBuffer。