String,StringBuffer,StringBuilder
String类
概念:String是不可变类,即一旦一个String对象被创建,包含在这个对象中的字符序列是不可改变的,直至该对象被销毁,并且String类是final类,不能有子类。
常用方法:
方法名 | 功能 |
---|---|
concat(String str) | 在末尾追加,并返回新的字符串 |
substring(int beginIndex) | 从开始下标处截取到字符串末尾,并返回新的字符串 |
substring(int beginIndex,int endIndex) | 从开始下标处(包含)截取到结束下标处(排他),并返回新的字符串 |
toLowerCase() | 转小写,并返回新的字符串 |
toUpperCase() | 转大写,并返回新的字符串 |
trim() | 去除首尾空格,并返回新的字符串 |
replace(char oldChar, char newChar) | 替换字符,并返回新的字符串 |
replaceAll(String old, String news) | 替换字符串,并返回新的字符串 |
replaceFirst(String old, String news) | 替换第一次出现的字符串,并返回新的字符串 |
equals(String str) | 判断两个字符串是否相同 |
equalsIgnoreCase(String str) | 判断两个字符串是否相同(不区分大小写) |
startsWith(String str) | 判断字符串是否以某个字符串开头 |
endsWith(String str) | 判断字符串是否以某个字符串结尾 |
indexOf(String str) | 查询出子字符串在字符串中第一次出现的下标 |
lastIndexOf(String str) | 查询出子字符串在字符串中最后一次出现的下标 |
charAt(int index) | 获取指定下标上的字符 |
代码实现:
public class Test01 {public static void main(String[] args) {String str = "123abc";str = str.concat("DEF123");System.out.println(str);//123abcDEF123str = str.substring(2);System.out.println(str);//3abcDEF123str = str.substring(1, 7);System.out.println(str);//abcDEFstr = str.toLowerCase();System.out.println(str);//abcdefstr = str.toUpperCase();System.out.println(str);//ABCDEFstr = " 123 abc DEF 123 ";str = str.trim();System.out.println(str);//123 abc DEF 123str = str.replace('2', '6');System.out.println(str);//163 abc DEF 163str = str.replaceAll("163", "666888");System.out.println(str);//666888 abc DEF 666888str = str.replaceFirst("666", "7777");System.out.println(str);//7777888 abc DEF 666888str = str.replaceAll(" ", "");System.out.println(str);//7777888abcDEF666888System.out.println("判断两个字符串是否相同(区分大小写):" + str.equals("7777888abcDEF666888"));//trueSystem.out.println("判断两个字符串是否相同(不区分大小写):" + str.equalsIgnoreCase("7777888ABCDEF666888"));//trueSystem.out.println("判断字符串是否以某个字符串开头:" + str.startsWith("777"));//trueSystem.out.println("判断字符串是否以某个字符串结尾:" + str.endsWith("666888"));//trueSystem.out.println("查询出子字符串在字符串中第一次出现的下标:" + str.indexOf("88"));//4System.out.println("查询出子字符串在字符串中最后一次出现的下标:" + str.lastIndexOf("88"));//17System.out.println("获取指定下标上的字符:" + str.charAt(7));//aSystem.out.println(str);//7777888abcDEF666888}
}
其他类型转String类型
方法一:valueOf()方法
System.out.println(String.valueOf(100));//int -> String
System.out.println(String.valueOf(123.123));//double -> String
System.out.println(String.valueOf('a'));//char -> String
System.out.println(String.valueOf(true));//boolean -> String
System.out.println(String.valueOf(new char[]{'a','b','c'}));//char[] -> String
方法二:直接拼接一个空串
System.out.println(100 + "");
System.out.println(123.123 + "");
System.out.println('a' + "");
System.out.println(true + "");
String创建对象个数
//以下创建了几个对象?
String str1 = "abc";
String str2 = "abc";
System.out.println(str1);
System.out.println(str2);
答案:1个
原因:常量池里面的数据是唯一的
//下列代码会创建几个对象
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1);
System.out.println(str2);
答案:3个
原因:在类加载时,会把字面值常量(abc)加载到常量池,然后上述代码又new了2个对象,因此一共是3个对象
//下列代码会创建几个对象
String a = "hello"+"abc";
答案:1个
原因:在编译时会优化,等价于String a = "helloabc";
//下列代码会创建几个对象
String a = "hello";
String b = "abc";
String c = a + b;
答案:3个
原因:1.先创建一个StringBuilder ab = StringBuilder()2.执行sb.append("hello");3.执行sb.append(“abc”);4.调用StringBuilder.java类的toString()方法,并且return new String()
图解:
String拼接创建对象
String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2);
结果:true
原因:常量池中的对象唯一
String str1 = "abc";
String str3 = "ab" + "c";
System.out.println(str1 == str3);
final String s1 = "ab";
final String s2 = "c";
String str4 = s1 + s2
System.out.println(str1 == str4)
结果:都为true
原因:两个常量在编译时会直接拼接
String str1 = "abc";
String s3 = "ab";
String s4 = "c";
String str5 = s3 + s4;
System.out.println(str1 == str5)
结果:false
原因:底层实现为:String str5 = (new StringBuilder(String.valueOf(s3))).append(s4).toString()
Stringbuilder类
概念:代表可变的字符序列,称为字符串缓冲区,预先申请一块内存,存放字符序列,如果字符序列满了,会重新改变缓存区的大小,以容纳更多的字符序列。
常用方法:
方法名 | 功能 |
---|---|
append(String str) | 末尾追加字符串 |
insert(int index,String str) | 将字符串插入到指定下标的位置 |
setCharAt(int index, Char char) | 替换指定下标上的字符 |
replace(int beginIndex,int endIndex,String str) | 替换开始下标处(包含)到结束下标处(排他)的字符串 |
deleteCharAt(int index) | 删除指定下标上的字符 |
delete(int beginIndex, int endIndex) | 删除开始下标处(包含)到结束下标处(排他)的字符串 |
reverse() | 反转字符串 |
代码实现:
public class Test01 {public static void main(String[] args) {StringBuilder sb = new StringBuilder();sb.append("123abc");sb.append("DEF123");System.out.println(sb);//123abcDEF123sb.insert(6, "XXYYZZ");System.out.println(sb);//123abcXXYYZZDEF123sb.setCharAt(6, 'x');System.out.println(sb);//123abcxXYYZZDEF123sb.replace(3, 6, "aabbcc");System.out.println(sb);//123aabbccxXYYZZDEF123sb.deleteCharAt(3);System.out.println(sb);//123abbccxXYYZZDEF123sb.delete(3, 17);System.out.println(sb);//123123sb.reverse();System.out.println(sb);//321321System.out.println(sb.toString());//321321}
}
深入了解StringBuilder
StringBuilder 的底层实现:
abstract class AbstractStringBuilder {//字符容器 - 34//['n','u','l','l','a','a','a','a','a','b','b','b','b','b','c','c','c','c','c'...]char[] value;//有效字符数int count;//24//capacity - 16AbstractStringBuilder(int capacity) {value = new char[capacity];}//str - "cccccccccc"public AbstractStringBuilder append(String str) {if (str == null)return appendNull();int len = str.length();//len - 10ensureCapacityInternal(count + len);//14 + 10//将str下标为0开始的数据添加到value数组count下标的位置,拷贝len长度str.getChars(0, len, value, count);count += len;return this;}private AbstractStringBuilder appendNull() {int c = count;//c - 0ensureCapacityInternal(c + 4);//扩容 -> 0+4final char[] value = this.value;value[c++] = 'n';//value[0] = 'n';value[c++] = 'u';//value[1] = 'u';value[c++] = 'l';//value[2] = 'l';value[c++] = 'l';//value[3] = 'l';count = c;return this;}//minimumCapacity - 24private void ensureCapacityInternal(int minimumCapacity) {// 有溢出意识的代码//if(24 - 16 > 0)if (minimumCapacity - value.length > 0) {//value = Arrays.copyOf(value,34);value = Arrays.copyOf(value,newCapacity(minimumCapacity));}}//面试题:StringBuilder的扩容机制为什么是原来的2倍+2//答:因为怕用户使用new StringBuilder(0)来创建对象,0<<1还是0,所以要加个2//minCapacity - 24private int newCapacity(int minCapacity) {//扩容机制:数组原来长度的2倍+2//int newCapacity = (16 << 1) + 2; --- 34int newCapacity = (value.length << 1) + 2;if (newCapacity - minCapacity < 0) {newCapacity = minCapacity;}return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)? hugeCapacity(minCapacity): newCapacity;}
}
public final class StringBuffer extends AbstractStringBuilder{public StringBuffer() {super(16);}public StringBuffer(int capacity) {super(capacity);}public StringBuffer(String str) {super(str.length() + 16);append(str);}@Overridepublic synchronized StringBuffer append(String str) {//自动上锁toStringCache = null;super.append(str);return this;}//自动解锁}
//默认长度:10000
//StringBuffer sb = new StringBuffer(10000);//默认长度:"abc".length() + 16
//StringBuffer sb = new StringBuffer("abc");//默认长度:16
StringBuffer sb = new StringBuffer();
String str = null;
sb.append(str);
sb.append("aaaaa");
sb.append("bbbbb");
sb.append("cccccccccc");
System.out.println(sb.toString());
StringBuffer类
StringBuffer 类是可变字符串类,创建 StringBuffer 类的对象后可以随意修改字符串的内容。每个 StringBuffer 类的对象都能够存储指定容量的字符串,如果字符串的长度超过了 StringBuffer 类对象的容量,则该对象的容量会自动扩大。所拥有的方法和StringBuilder类相同。
String VS StringBuilder VS StringBuffer
- 值的可变性
- String内部的value值是final修饰的,所以,它是不可变类;因此每次修改String的值,都会在常量池产生一个新的对象。
- StringBuffer和StringBuilder是可变类,它们在字符串变更的时候,不会创建新的对象。
- 线程安全
- String是不可变类,所以它是线程安全的。
- StringBuilder不是线程安全的。
- StringBuffer是线程安全的,因为它的每个操作方法都加了synchronized同步关键字。
- 使用选择
- 如果要操作少量的数据用 String。
- 多线程操作字符串缓冲区下操作大量数据 StringBuffer。
- 单线程操作字符串缓冲区下操作大量数据 StringBuilder,因为不用上锁。
- 值的可变性
- String内部的value值是final修饰的,所以,它是不可变类;因此每次修改String的值,都会在常量池产生一个新的对象。
- StringBuffer和StringBuilder是可变类,它们在字符串变更的时候,不会创建新的对象。
- 线程安全
- String是不可变类,所以它是线程安全的。
- StringBuilder不是线程安全的。
- StringBuffer是线程安全的,因为它的每个操作方法都加了synchronized同步关键字。
- 使用选择
- 如果要操作少量的数据用 String。
- 多线程操作字符串缓冲区下操作大量数据 StringBuffer。
- 单线程操作字符串缓冲区下操作大量数据 StringBuilder,因为不用上锁。