String,StringBuffer,StringBuilder知识梳理
String类
是不可变的对象,即每次要对String对象进行修改时,都会重新创建一个新的String对象,然后指向这个新对象。
创建方式有两种:
1. String s = "abc"; //先查看常量池有无"abc"数据空间,如果有直接指向,没有就在常量池中创建一个,然后指向
2. String s = new String ("abc"); //现在堆中创建一块空间,维护了value属性,然后这块空间指向常量池中的"abc",如果常量池没有,同上
String常用方法:
int length(): 返回字符串的长度
char charAt(int index): 返回指定索引处的字符
boolean isEmpty(): 判断字符串是否为空
String toLowerCase(): 将字符串中的所有字符转换为小写
String toUpperCase(): 将字符串中的所有字符转换为大写
String trim(): 返回字符串的副本,去掉前导空白和尾部空白,中间的空白不会被去掉
boolean equals(Object obj): 比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString): 忽略大小写,比较字符串的内容是否相同
String concat(String str): 将指定字符串连接到此字符串的结尾,等价于用“+”
int compareTo(String anotherString): 比较两个字符串的大小
String substring(int beginIndex): 返回从beginIndex到末尾的子字符串
String substring(int beginIndex, int endIndex): 返回从beginIndex到endIndex-1的子字符串,不包括endIndexboolean endsWith(String suffix): 判断字符串是否以指定的后缀结束
boolean startsWith(String prefix): 判断字符串是否以指定的前缀开始
boolean startsWith(String prefix, int toffset): 判断字符串在指定索引开始的子字符串是否以指定前缀开始
boolean contains(CharSequence s): 判断当前字符串中是否包含指定的字符串int indexOf(String str): 返回指定子字符串在当前字符串中第一次出现处的索引
int indexOf(String str, int fromIndex): 返回从指定的索引后,指定子字符串在当前字符串中第一次出现处的索引
int lastIndexOf(String str): 返回指定子字符串在当前字符串中最后一次出现处的索引
int lastIndexOf(String str, int fromIndex): 返回从指定的索引后,指定子字符串在当前字符串中最后一次出现处的索引
注:indexOf和lastIndexOf方法如果未查找到指定子字符串时,返回值都为-1。String replace(char oldChar, char newChar): 替换当前字符串中指定的子字符串
String[] split(String regex): 根据指定的符号拆分当前字符串,然后返回一个String数组
String和char[]相互转换
//String-->char[]String s1 = new String("123jslas");char [] c1 = s1.toCharArray();System.out.println(c1);//char[]-->Stringchar [] c2 = {79,'c','s','a'};String s2 = new String (c2);System.out.println(s2);
String和byte[]互相转换,使用String的getBytes方法,同理
特性:
String a = "abc"; //创建了一个a对象
String b = "ee"; //创建了一个b对象
String c = a+b; //创建了三个对象,分别是"abcee"这个字符串常量,Stringbuilder对象,String对象
因为String t1 = "a"+"b"是常量相加,看的是池
而String t2 = a+"123"是有变量参与的相加,是在堆中。这种相加底层是StringBuilder t2 = new StringBuilder();t2.append(a);t2.append("123"); t2是在堆中。
总结:当变量与字面量或变量与变量进行拼接时,会在堆中创建一个StringBuilde对象,然后使用StringBuilder的append()方法将变量与字面量或变量与变量进行拼接,最后调用toString()方法转成String对象。
StringBuffer (线程安全)
底层也是用一个数组来存储字符串的值
如果调用无参构造器,数组长度默认为16
调用有参构造函数创建一个StringBuffer对象时,数组长度为“当前对象值的长度+16”
在用append添加字符常量时,先判断添加之后的长度是否大于目前的容量,如果大的话,就要进行扩容
扩容
扩容的逻辑就是创建一个新的 char 数组,将现有容量扩大一倍再加上2,如果还是不够大则直接等于需要的容量大小。扩容完成之后,将原数组的内容复制到新数组,最后将指针指向新的 char 数组。
这个是Arrays类提供的静态方法,将原来的数组扩充到newLength长度,然后将原来的数据拷贝过去,可以从源码看出,它首先创建出一个新的字符数组,然后使用System的静态方法arraycopy将原来的数据拷贝到新的数组,然后返回新的数组。
StringBuffer类常用方法
增 append
s.append(","); s.append("小张").append("小王").append(11.4).append(true);
删 delete(start,end)
改 replace(start,end,String)
s.replace(11,14,“马化腾”);
查 indexOf //查找指定的子串在字符串中第一次出现的索引,找不到返回-1
int indexof = s.indexOf("马化腾");
插 insert
s.insert(9,"小张");
获取长度 length
String,StringBuffer相互转换
//String -- > StringBuffer//方法1String s1 = new String("demaxiya");StringBuffer b1 = new StringBuffer(s1);System.out.println(b1);//方法2StringBuffer b2 = new StringBuffer();b2.append(s1);//StringBuffer -- > String//方法1StringBuffer b3 = new StringBuffer("qigeai");String s3 = b3.toString();System.out.println(s3);//方法2String s4 = new String(b3);System.out.println(s4);
String、StringBuffer和StringBuilder的异同
相同点:底层都是通过char数组实现的
不同点:
String对象一旦创建,值不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;
StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。
如果我们在实际开发过程中需要对字符串进行频繁的修改,不要使用String,否则会造成内存空间的浪费;当需要考虑线程安全的场景下使用 StringBuffer,如果不需要考虑线程安全,追求效率的场景下可以使用 StringBuilder。