StringBuilder和StringBuffer
- 字符串的不可变性
- 字符串修改
- StringBuilder和StringBuffer
- 1 字符串拼接
- 2 获取、修改和删除下标字符
- 3 插入字符
- 4 字符串替换
- 5 字符串反转
- 6 StringBuffer和StringBuilder类与String类的转换
- StringBuffer和StringBuilder类的区别
前言
在Java中String是⼀种不可变对象.字符串中的内容是不可改变,有时候修改成功其实是创建临时变量,但有时候修改次数过多的话,就会影响代码的效率,所以Java提供了StringBuilder和StringBuffer用来修改字符串内容
字符串的不可变性
String是⼀种不可变对象,字符串中的内容是不可改变,字符串不可被修改
下面是JDK17中String的部分源码
在String源码中其实被final修饰的,final修饰的是常量,所以不可以修改,并且其内部有私有成员,因此其并不是真正的修改内容,String的不可变性质
字符串修改
public class Test {public static void main(String[] args) {String s = "abc";s = s +"def";System.out.println(s);}
}
运行结果如下
上面说其不可以被修改,为什么这里的结果却修改了呢,其实这里本质是创建了临时变量,其实是对新对象的修改,并不是修改了原本的对象
,因此这样的修改创建临时变量会影响代码的效率
我们从下面这个代码来直观的感受其效率
public static long currentTimeMillis()
返回值是:long长类型
功能:获取当前的时间,单位是毫秒
public class Test {public static void main(String[] args) {//获取当前时间long start = System.currentTimeMillis();String s = "";for (int i = 0; i < 10000; i++) {s+=i;}//循环结束的时间long end = System.currentTimeMillis();//相减就得到了,这个创建临时变量循环的时间System.out.println(end-start);}
}
这样我们使用一个循环来判断其所创建临时变量所浪费的时间,获取进入循环的时间和结束循环的时间,二者相减就获得了经过循环的时间
运行结果如下
这个效率其实是很慢的,这时候就要引入[StringBuilder]和[StringBuffer]
public class Test {public static void main(String[] args) {//获取当前时间//Stringlong start = System.currentTimeMillis();String s = "";for (int i = 0; i < 10000; i++) {s += i;}//循环结束的时间long end = System.currentTimeMillis();//相减就得到了,这个创建临时变量循环的时间System.out.println("String的时间:"+(end - start));//StringBuilderlong start1 = System.currentTimeMillis();StringBuilder stringBuilder = new StringBuilder("");for (int i = 0; i < 10000; i++) {stringBuilder.append(i);//拼接}long end1 = System.currentTimeMillis();System.out.println("StringBuilder的时间:"+(end1-start1));//StringBufferlong start2 = System.currentTimeMillis();StringBuffer stringBuffer = new StringBuffer("");for (int i = 0; i <10000 ; i++) {stringBuffer.append(i);}long end2 = System.currentTimeMillis();System.out.println("StringBuffer的时间:"+(end2-start2));}
}
运行结果如下
虽然这个运行速率有所改变,但是这里的StringBuffer与StringBuilder的速率相近并且接近于0,String类的速率较慢
从结果中可以看出可以看到在对String类进⾏拼接时,效率是⾮常慢,因此:尽量避免对String的直接需要,如果要修改建议尽量使⽤StringBuffer或者StringBuilder
StringBuilder和StringBuffer
StringBuilder和StringBuffer与String使用类似,但是也有一些其String没有的方法
方法 | 说明 |
---|---|
StringBuffer append(String str) | 尾部追加 |
char charAt(int index) | 获取index下标的字符 |
int length() | 获取字符串长度 |
int capacity() | 获取底层保存字符串空间 |
ensureCapacity(int minimumCapacity) | 扩容 |
setCharAt(int index, char ch) | 将index下标字符改为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) | 从fromIndex下标开始找str第一次出现的位置 |
int lastIndexOf(String str) | 从后向前找返回str第一次出现的位置 |
int lastIndexOf(String str, int fromIndex) | 从最后到fromIndex下标开始找str第一次出现的位置 |
StringBuffer insert(int offset, String c) | 在offset插入:八种基本类型与String类 |
StringBuffer deleteCharAt(int index) | 删除index下标字符 |
StringBuffer delete(int start, int end) | 删除从[start,end)下标字符 |
StringBuffer replace(int start, int end, String str) | 将[start,end)下标字符替换为str |
String substring(int start) | 从start下标开始一直到末尾存储到一个新的String类中 |
String substring(int start, int end) | [start,end)下标存储到一个新的String类中 |
StringBuffer reverse() | 将字符串进行反转 |
String toString() | 将所有字符按照String方式返回 |
这里的StringBuilder和StringBuffer方法类似,所以下面只以StringBuffer举例
1 字符串拼接
append(String str)
将str字符串拼接到后面
这个可以将基本八种类型&String类型都可以进行拼接
public class Test {public static void main(String[] args) {StringBuffer stringBuffer = new StringBuffer("");stringBuffer.append(" ");stringBuffer.append("hello");System.out.println(stringBuffer);StringBuilder stringBuilder = new StringBuilder("");stringBuilder.append(" ");stringBuilder.append("hello");System.out.println(stringBuilder);}
}
运行结果如下
2 获取、修改和删除下标字符
1.获取下标字符
char charAt(index)
获取index下标字符
返回char类型
StringBuffer stringBuffer = new StringBuffer("abc");char ch = stringBuffer.charAt(1);System.out.println(ch);
运行结果如下
2.修改下标字符
char setCharAt(index)
获取index下标字符
返回void类型
public class Test {public static void main(String[] args) {StringBuffer stringBuffer = new StringBuffer("abc");System.out.println("修改前:"+stringBuffer.charAt(1));// - 获取1下标的字符--’b'stringBuffer.setCharAt(1,'m');//修改1下标字符System.out.println("修改后:"+stringBuffer.charAt(1));}
}
)
注意:这里由于返回的是void类型,所以这里只是对 StringBuffer修改,不可以直接打印
如果直接打印其修改过程,编译器就会报错
3.删除下标字符
deleteCharAt(int index)删除index下标字符
deleteCharAt(int start,int end)删除[start,end)下标字符
返回值都是void
public class Test {public static void main(String[] args) {StringBuffer stringBuffer = new StringBuffer("abcdef");System.out.println("修改前:"+stringBuffer.charAt(1));// - 获取1下标的字符--’b'stringBuffer.setCharAt(1,'m');//修改1下标字符System.out.println("修改后1下标后:"+stringBuffer);stringBuffer.deleteCharAt(1);//删除指定下标System.out.println("删除1下标后:"+stringBuffer);//删除下标区间的字符stringBuffer.delete(1,5);System.out.println("删除[1,5)下标字符后:"+stringBuffer);}
}
这里首先打印1下标字符,其次修改1下标字符为’m’,其次删除1下标字符,最后删除[1,5)下标字符后的stringBuffer
3 插入字符
insert(int offset, String str)
在offset插入字符串str
这里的str需要插入的可以是基本八种类型和String类
但是本质还是将其转化为字符串表示形式进行插入
public class Test {public static void main(String[] args) {StringBuffer stringBuffer = new StringBuffer("aaaaa");stringBuffer.insert(1,"___");System.out.println(stringBuffer);stringBuffer.insert(3,3.12);System.out.println(stringBuffer);}
}
第一次是从1下标开始插入_ _ _
第二次会在其基础上的从3下标开始插入3.12,虽然是double类型,其实本质还是插入字符串类型
4 字符串替换
replace(int start, int end, String str)
将[start,end)下标字符替换为字符串str
如果str长度<这个区间的长度,从前向后替换,替换后多余的变成“”空白,字符串内容会减少
如果str长度>这个区间长度,编译器会自动扩容把这个字符串全部放进去,只修改[start,end)区间的字符,其他的不会修改
str字符串长度等于[start,end)区间长度
public class Test {public static void main(String[] args) {StringBuffer stringBuffer = new StringBuffer("aaaaaa");System.out.println("原本其长度:"+stringBuffer.length());stringBuffer.replace(0,4,"AAAA");System.out.println(stringBuffer);System.out.println("取代后长度:"+stringBuffer.length());}
}
这里取代的字符串长度是等于[0,4)这个区间的大小的,都是为4,这是正常取代
原本字符串长度没有改变
str字符串长度小于[start,end)区间长度
public class Test {public static void main(String[] args) {StringBuffer stringBuffer = new StringBuffer("aaaaaa");System.out.println("原本其长度:"+stringBuffer.length());stringBuffer.replace(0,4,"AA");System.out.println(stringBuffer);System.out.println("取代后长度:"+stringBuffer.length());}
}
这里我们是准备将[0,4)区间的字符替换为str的,但是这个str长度小于[start,end)区间长度
这个时候在取代的时候,编译器会将其区间替换,可以理解为多余的会变成”“空白
这里相当于 ”AA"替换4个位置,从前向后,多的就直接相当于空
这时候编译器会自动减小字符串长度
str字符串长度大于[start,end)区间长度
public class Test {public static void main(String[] args) {StringBuffer stringBuffer = new StringBuffer("aaaaaa");System.out.println("原本其长度:"+stringBuffer.length());stringBuffer.replace(0,4,"AAAAAAAAAAA");System.out.println(stringBuffer);System.out.println("取代后长度:"+stringBuffer.length());}
}
这时候str字符串长度大于[0,4)区间长度,它不管你是否够方下,它直接将这些字符全部放在从start下标开始,直到放完结束,[0,4)下标以外的字符不会修改,只是下标可能变了,其实这里相当于给字符串扩容了
5 字符串反转
reverse()字符串反转
public class Test {public static void main(String[] args) {StringBuffer stringBuffer = new StringBuffer("hello");System.out.println("反转前:"+stringBuffer);stringBuffer.reverse();System.out.println("反转后:"+stringBuffer);}
}
6 StringBuffer和StringBuilder类与String类的转换
直接转化的话是不可以的,编译器会报错
**toString()**方法将StringBuffer类转化为String类
public class Test {public static void main(String[] args) {StringBuffer stringBuffer = new StringBuffer("bbb");StringBuilder stringBuilder = new StringBuilder("ccc");String string = new String("aaa");//将其转化为String赋值string = stringBuffer.toString();System.out.println(string);string = stringBuilder.toString();System.out.println(string);}
}
运行结果如下,这里是不可以直接赋值,需要使用toString方法转化为String类
StringBuffer和StringBuilder类的区别
StringBuffer和StringBuilder从⽅法的功能上来说没有太⼤区别
但是二者方法内部有区别
StringBuffer和StringBuilder类的区别
1 方法功能都是一样的
2 其 StringBuffer类中的方法,前面多了一个synchronized修饰,这个相当于一个锁,有人使用就把锁锁上,使用完离开就将锁打开
3 因此StringBuffer是同步处理,是线程安全的,而StringBuilder类没有采取同步处理,线程不安全
到这里就结束了,预知后事如何,请听下回分解