StringBuffer 和 StringBuilder
字符串
1.什么是字符串?
- 字符串基本概念
-
- 字符串是0个或多个字符的有序集合
-
- 在Java中,字符串 String 是一个类,它封装了字符串数据和诸多操作方法;所有的方法都不能修改字符串本身,因此,Java中的字符串是一个常量
-
- 本质上,String 类中使用一个char[]来存储字符串
注:我们学习字符串,其实就是学习字符串的操作方法
- 本质上,String 类中使用一个char[]来存储字符串
-
2.字符串的使用
2.1 创建字符串
语法
String s1="abc"; //语法一
String s2=new String("cde"); //语法二
两种语法的区别(内存结构图)
语法一内存结构图
语法二
注:在语法二的代码中实际上创建了2个对象(面试题)
2.2 字符串方法
1. 获取字符串长度
String s="abc";
System.out.println(s.length());
2. 字符串比较
String s1=new String("abc");
String s2=new String("abc");
System.out.println(s1==s2); //false
System.out.println(s1.equals(s2));//true
注:
1. 双等符号比较的是内存地址
2. equals()方法比较的是字符串的内容
面试题1:如下代码的结果是什么?
String s1="abc";
String s2="abc";
System.out.println(s1==s2);//true
以上代码的内存结构图
面试题2:如下代码的结果是什么?
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
以上代码的内存结构图
3. 字符串比较的其他方法
String s1 = "abc";
String s2 = "ABC";
System.out.println(s1.equals(s2)); // false
System.out.println(s1.equalsIgnoreCase(s2)); // true
System.out.println(s1.toLowerCase.equals(s2.toLowerCase())); // true
System.out.println(s1.toUpperCase.equals(s2.toUpperCase())); // true
1. boolean s1.equalsIgnoreCase(String s2) 忽略大小写比较字符串
2. String s1.toUpperCase() 将字符串转换为大写
3. String s1.toLowerCase() 将字符串转换为小写
4. 字符串连接
int java = 100;
int c = 98;
System.out.println("java : " + java);
System.out.println("c : ".concat(c + ""));
1. 使用 + 拼接字符串
2. String s1.concat(String s2) 拼接字符串
3. 拼接字符串的结果是生成一个新的拼接后的字符串,原字符串不变。
5. 字符串查找
String s1 = "This is a bus.";
int p1 = s1.indexOf("is"); // p1 : 2
int p2 = s1.lastIndexOf("is"); // p2 : 5
int p3 = s1.indexOf("ab"); // p3 : -1
1. int s1.indexOf(String s2) 在主串 s1 中查找子串 s2 的位置,如果找不到,
返回 -1;
2. int s1.indexOf(char c) 在主串 s1 中查找字符 c 的位置,如果找不到,返回
-1;
3. int s1.lastIndexOf(String s2) 在主串 s1 中查找子串 s2 的位置,如果找不
到,返回 -1;
4. int s1.lastIndexOf(char c) 在主串 s1 中反向查找字符 c 的位置,如果找不
到,返回 -1;
6. 字符串截取
String s1 = "abcdefg ";
String s2 = s1.substring(3, 5); // s2 : de
String s3 = s1.substring(3); // s3 : defg
String s4 = s1.trim(); // s4 : abcdefg
1. String s1.substring(int pos1, int pos2) 在主串 s1 中截取子串,子串范围
从主串的 pos1 位置开始到 pos2 - 1 为止;
2. String s1.substring(int pos) 在主串 s1 中截取子串,子串范围从主串的
pos1 位置开始到主串结束位置;
3. String s1.trim() 将 s1 首尾的空格去除。
7. 字符串拆分
String s1 = "086-0379-3995995";
String[] a = s1.split("-"); // a : {"086", "0379", "3995995"}
String[] s1.split(String s2) 将主串 s1 按照子串 s2 劈开,结果是分解成若干个子串,
返回这些子串的数组;
String不为人知的秘密
public class Test {
public static void main(String[] args) {
//String 是被 final 修饰的 每次更改都会重新开辟一个新的内存地址
String s1=new String("a");
String s2=new String("a");
//==比较的是内存地址
//equals在string里面比较的是值
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
String s3="b";//指向同一个内存地址
String s4="b";
System.out.println(s3==s4);//true
System.out.println(s3.equals(s4));//true
}
}
String
和 StringBuffer
在 Java 中都用于处理字符串,但它们之间存在一些重要的区别。
- 不可变性:
String
是不可变的。这意味着一旦创建了一个String
对象,就不能更改它。每次对String
进行修改,都会创建一个新的String
对象。这可能会导致内存和性能问题,特别是在处理大量字符串操作时。
String s = "Hello";
s = s + " World"; // s now refers to a new String object
另一方面,StringBuffer
是可变的。这意味着可以修改 StringBuffer
对象本身,而不会创建新的对象。
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World"); // The original StringBuffer is modified
- 性能:
由于String
的不可变性,对于需要大量修改字符串的操作,使用StringBuffer
通常会更快。在处理大量字符串连接或修改操作时,使用String
可能会导致大量的对象创建和垃圾收集。 - 线程安全:
StringBuffer
是线程安全的,因为它的大多数方法都是同步的。这意味着多个线程可以同时操作同一个StringBuffer
对象,而不会导致数据不一致。
相比之下,String
的不可变性使其线程安全,因为没有方法可以修改 String
对象。但是,对于可变字符串操作(如字符串连接),可能需要额外的同步措施来确保线程安全。
4. 用途:
String
更适合于表示不可变的数据或常量,例如文件路径或消息字符串。
另一方面,StringBuffer
更适合于需要修改的字符串,例如在拼接或修改字符串时。
5. 内存占用:
由于 StringBuffer
的可变性,它通常会占用更多的内存。因此,在内存敏感的应用程序中,应优先考虑使用 String
。
6. 方法:
StringBuffer
提供了一组更丰富的方法来修改字符串,例如 append()
, insert()
, delete()
, replace()
等。相比之下,String
只提供了一些基本的字符串操作方法。
StringBuffer 和 StringBuilder的区别
StringBuffer
和StringBuilder
都用于处理可变字符串,但它们之间存在一些重要的区别。
- 线程安全:
StringBuffer
是线程安全的,因为它的所有方法都是同步的。这意味着多个线程可以同时操作同一个StringBuffer
对象,而不会导致数据不一致。
相比之下,StringBuilder
不是线程安全的。它的方法没有同步机制,因此在多线程环境下可能会引发问题。然而,由于其非线程安全的特性,StringBuilder
在单线程环境下的性能通常会优于 StringBuffer
。
2. 性能:
在性能方面,StringBuilder
通常要优于 StringBuffer
,尤其是在没有多线程冲突的情况下。这是因为 StringBuilder
的方法没有进行同步处理,所以执行起来会更快。
3. 用途:
如果你在单线程环境下工作,或者需要更高的性能,那么 StringBuilder
是一个更好的选择。如果你在多线程环境下工作,且需要确保线程安全,那么 StringBuffer
是更适合的选择。
总的来说,选择 StringBuffer
还是 StringBuilder
,主要取决于你的应用场景和需求。
StringBuffer
StringBuffer stringBuffer=new StringBuffer("ABC");
StringBuffer stringBuffer1=stringBuffer.append("DEF");
System.out.println(stringBuffer==stringBuffer1);
StringBuffer 的优点
由于 String 对象是常量(实际上是使用了不变模式),所以在进行频繁的字符串拼接、插入、
删除操作时,会产生大量的内存垃圾;此时,因选择 StringBuffer 或者 StringBuilder类。
StringBuffer 的使用
StringBuffer 拥有几乎 String 的所有方法,只是实现方式有所不同;StringBuffer 还拥有 String所没有的方法。
1. 追加字符串
StringBuffer sb = new StringBuffer("学 IT"); // sb : 学 IT
StringBuffer sb1 = sb.append("好工作"); // sb, sb1 : 学 IT好工作
StringBuffer sb2 = sb.append("高端大气上档次"); // sb, sb1, sb2 : 学 IT好工作高端大气上档次
String s1.append(String s2) 在字符串 s1 后追加字符串 s2,并返回 s1;
以上代码的内存结构图
2. 插入字符串
StringBuffer sb1 = new StringBuffer("abc");
sb1.insert(1, "123"); // sb1 : "a123bc"
String s1.insert(int pos, String s2) 在字符串 s1 的 pos 位置插入字符串 s2,并返回s1。
StringBuilder
3.1 StringBuilder概述
StringBuilder 是一个可变的字符串类,我们可以把它看成是一个容器
这里的可变指的是StringBuilder对象中的内容是可变的
String 和 StringBuilder的区别:
- String:内容是不可变的
- StringBuilder:内容是可变的
3.2 StringBuilder 构造方法
方法名 | 说明 |
---|---|
public StringBuilder() | 创建一个空白可变字符串对象,不含有任何内容 |
public StringBuilder(String str) | 根据字符串的内容,来创建可变字符串对象 |
public class StringDemo01 {
public static void main(String[] args) {
//public String():创建一个空白字符串对象,不含有任何内容
String s1=new String();
System.out.println("s1"+s1);
//public String(char[] chs):根据字符数组内容 来创建字符串对象
char[] chs={'a','b','c'};
String s2=new String(chs);
System.out.println("s2:"+s2);
//public String(byte[] bys):根据字节数组内容,来创建字符串对象
byte[] bys={97,98,99,100};
String s3=new String(bys);
System.out.println("s3:"+s3);
//String s="abc"; 直接赋值的方法创建字符串对象,内容就是abc
String s4="abc";
System.out.println("s4:"+s4);
//获取字符串长度
System.out.println(s4.length());
//遍历字符串
for (int i = 0; i < s4.length(); i++) {
System.out.println(s4.charAt(i));
}
}
}
3.3 StringBuilder 添加和反转
链式编程
public class StringBuliderDemo02 {
public static void main(String[] args) {
//创建对象
StringBuilder s = new StringBuilder();
//public StringBuilder oppend(任意类型):添加数据 并返回对象本身
// StringBuilder s2=s.append("hello");
//
// System.out.println("s:"+s);
// System.out.println("s2:"+s2);
// System.out.println(s==s2);
// s.append("hello");
// s.append("world");
// s.append("java");
// s.append(100);
//链式编程
s.append("hello ").append("world ").append("Java ").append(100);
//s:hello world Java 100
System.out.println("s:" + s);
//public StringBuilder reverse():返回相反的字符序列
s.reverse();
//s:001 avaJ dlrow olleh
System.out.println("s:" + s);
}
}
3.4 StringBuilder 和String相互转换
1.StringBuilder转换为String
public String toString():通过toString()就可以实现把StringBuilder转换为String
2. String转换为StringBuilder
public StringBuilder(String s):通过构造方法就可以实现把String转换为StringBuilder
public class StringBuilderDemo03 {
public static void main(String[] args) {
//StringBuilder转换为 String
StringBuilder s=new StringBuilder();
s.append("hello");
System.out.println(s);
String s1=s.toString();
System.out.println(s1);
//String 转换为 StringBuilder
String s2="hello";
StringBuilder s3=new StringBuilder(s2);
System.out.println(s3);
}
}
StringBuilder 案例:拼接字符串
需求: 定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果。例如,数组为int[] arr={1,2,3};,执行方法后的输出结果为:[1,2,3]
思路:
① 定义一个int类型的数组,用静态初始化完成数组元素的初始化
② 定义一个方法,用于把int数组中的数据按照指定格式拼接成一个字符串返回,返回值类型String,参数列表int[] arr
③ 在方法中用StringBuilder按照要求进行拼接,并把结果转成String返回
④ 调用方法,用一个变量接收结果
⑤ 输出结果
public class StringBuilderTest01 {
public static void main(String[] args) {
//① 定义一个int类型的数组,用静态初始化完成数组元素的初始化
int[] arr={1,2,3};
// ④ 调用方法,用一个变量接收结果
String s = arrayToString(arr);
System.out.println("s:"+s);
}
//② 定义一个方法,用于把int数组中的数据按照指定格式拼接成一个字符串返回,返回值类型String,参数列表int[] arr
/*
两个明确:
返回值类型:String
参数: int[] arr
*/
public static String arrayToString(int[] arr){
//③ 在方法中用StringBuilder按照要求进行拼接,并把结果转成String返回
StringBuilder s=new StringBuilder();
s.append("[");
for (int i=0;i<arr.length;i++){
if (i==arr.length-1){
s.append(arr[i]);
}else{
//拼接
s.append(arr[i]).append(",");
}
}
s.append("]");
String s1=s.toString();
return s1;
}
}
StringBuilder 案例:字符串反转
需求: 定义一个方法,实现字符串反转。键盘录入一个字符串,调用该方法后,在控制台输出结果
例如,键盘录入abc,输出结果cba
思路:
① 键盘录入一个字符串,用 Scanner 实现
② 定义一个方法,实现字符串反转,返回值类型 String,参数 String s
③ 在方法中用 StringBuilder 实现字符串的反转,并把结果转成 String 返回
④ 调用方法,用一个变量接收结果
⑤ 输出结果
3.5 通过帮助文档查看 StringBuilder 中的方法
方法名 | 说明 |
---|---|
public StringBuilder append(任意类型) | 添加数据,并返回对象本身 |
public StringBuilder reverse() | 返回相反的字符序列 |
public String toString() | 通过toString()就可以实现把StringBuilder转换为String |