声明: 此笔记通过观看【尚学堂】+(赖小平主编)清华大学出版社的《Java程序设计》感悟整理得出, 若有任何相关问题,请注明来源联系作者!
可变字符串StringBuilder与StringBuffer
在StringBuffer和StringBuiled类中存在很多和String类一样的方法,它们在功能上和String类完全一样,但是对StringBuffer和StringBuiled对象的每次修改都会改变其本身,这是和String最大的区别。
区别:StringBuilder线程不安全,效率高(一般会选择使用它);StringBuffer线程安全,效率低。
【实例 测试StringBuilder】
package stringbuilderandwrapper;
/**
* 测试StringBuilder
* @懒惰的小黑
*
*/
public class TestStringBuilder {
public static void main(String[] args) {
StringBuilder test = new StringBuilder("abcdefgh");
System.out.println(Integer.toHexString(test.hashCode())); //输出地址
System.out.println(test);
test.setCharAt(2, 'G');
System.out.println(Integer.toHexString(test.hashCode()));
System.out.println(test);
/*
* 由结果可知,对象的内容发生了改变,但地址相同,还是同一个对象。
*/
}
}
【执行结果】
注:
StringBuffer与String对象之间的相互转换:
StringBuffer和String属于不同类型,不能直接进行强制转化。
【实例 测试StringBuffer和String相互转换】
public class TestBuffer {
public static void main(String[] args) {
//StringBuffer s = new StringBuffer("abc");
//String s1 = (String)s; //编译错误,不能进行强制转换
//String类型转换为StringBuffer类型
String s1 = "abc";
StringBuffer sb1 = new StringBuffer(s1);
//StringBuffer类型转换为String类型
StringBuffer sb2 = new StringBuffer("abc");
String sb3 = sb2.toString();
}
}
StringBuilder与StringBuffer用法
常用方法:
1、 重载的public StringBuilder append(…)方法,可以为该StirngBuilder对象添加字符序列,仍然返回自身对象。
2、 方法public StringBuilder delete(int start,intend),可以删除从start开始到end-1为止的一段字符序列,仍然返回自身对象。
3、 方法public StringBuilder deleteCharAt(int index),移除此序列指定位置上的char,返回自身对象。
4、 重载的public StringBuilder insert(….)方法可以为该StringBuilder 对象在指定位置插入字符序列,仍然返回自身对象。
5、 方法public StringBuilder reverse() 用于将字符序列逆序,仍然返回自身对象。
6、 方法public String toString() 返回此序列中数据的字符串表示形式
7、 还有和String类含义类似的方法
注:返回自身对象可以进行链式调用。具体看下面实例
【实例 StringBuilder与StringBuffer的基本用法】
package stringbuilderandwrapper;
/**
* 测试StringBuilder与StringBuffer常用方法
* @懒惰的小黑
*
*/
public class TestStringBuilderMethod {
public static void main(String[] args) {
//测试StringBuilder常用方法
StringBuilder sb = new StringBuilder();
for(int i = 0 ;i<26;i++) {
char str =(char)('a' + i);
sb.append(str);
}
System.out.println(sb);
//提取索引为3的字符
char c = sb.charAt(3);
System.out.println(c);
//在索引为2的位置修改成一个字符'小'
sb.setCharAt(2, '小');
System.out.println(sb);
//倒序
sb.reverse();
System.out.println(sb);
//在指定的字符串索引位置插入指定的字符
sb.insert(3, '黑');
System.out.println(sb);
//链式调用插入的方法
sb.insert(1, '小').insert(2, '黑').insert(3, '黑');
System.out.println(sb);
//删除方法
sb.delete(2, 6);
System.out.println(sb);
}
}
【执行结果】
注:StringBuffer调用方法与StringBuilder同理
可变字符串和不可变字符串的使用陷阱
String是不可变字符串,初始化后不会再改变其内容,对string字符串操作实质是生成了一个新的副本,对原来的字符串没有一点改变。
String s = “a”;
s = s +”b”;实际上“a”字符串的对象已经丢弃了,而又产生了另一个字符串s + “b”(就是“ab”)。如果多次执行这些改变字符串的操作,会导致出现大量的副本字符串对象存留在内存中,降低了效率,若放到循环中,会极大的影响时间和空间的性能,甚至会造成服务器的崩溃。
【实例 测试可变字符串和不可变字符串的使用陷阱】
package stringbuilderandwrapper;
/**
* 测试可变字符串和不可变字符串的使用陷阱
* @懒惰的小黑
*
*/
public class TestStringBuilderproblem {
public static void main(String[] args) {
//使用string进行字符串拼接(不建议使用此操作)
String str = "";
long num = Runtime.getRuntime().freeMemory(); //获取系统剩余内存
long time = System.currentTimeMillis(); //获取系统当前时间
for(int i = 0;i<3000;i++) {
str = str + i;
//产生了6000个对象,每循环一次产生 i 个对象 + 与 i连接后的对象,共2个对象
}
long num01 = Runtime.getRuntime().freeMemory();
long time01 = System.currentTimeMillis();
System.out.println("String占用的内存:" + (num-num01)); //占用了多少内存
System.out.println("String占用的时间:" + (time01-time)); //所需时间
//使用StringBuilder进行字符串拼接
StringBuilder str01 = new StringBuilder();
long num02 = Runtime.getRuntime().freeMemory(); //获取系统剩余内存
long time02 = System.currentTimeMillis(); //获取系统当前时间
for(int i = 0;i<3000;i++) {
str01.append(i); //相当于在原来的对象进行增加
}
long num03 = Runtime.getRuntime().freeMemory(); //获取系统剩余内存
long time03 = System.currentTimeMillis(); //获取系统当前时间
System.out.println("StringBuilder占用的内存:" + (num02-num03)); //占用了多少内存
System.out.println("StringBuilder占用的时间:" + (time03-time02)); //所需时间
}
}
【执行结果】
注:由此可知当StringBuilder对象调用append会大大优化程序,减少内存的浪费。所以无论循环多少次,一般在工作中都会使用此方法(看具体问题分析)。