目录
关于String类
Java中的String类是不可变的 这意味着一旦一个String对象被创建 它包含的字符序列就不能被改变
这里我们可能会想到字符串拼接--->"+"
实际上 当我们执行字符串拼接时 会创建一个新的String对象来存储拼接后的结果 原有的String对象仍然保持不变 存在于内存中 直到垃圾回收器将其回收
示例:
String s1 = "Hello";
String s2 = "World";
String s3 = s1 + ", " + s2; // 字符串拼接
在这里s3并不是通过修改s1或s2来得到的 而是java运行时 在内存中创建了一个新的String对象来存储"Hello,World"这个字符串 并将s3引用指向了这个新对象
由于String的不可变性 为了方便字符串的修改 Java中又提供了StringBuffer和StringBuilder类
StringBuilder和StringBuffer
StringBuffer与StringBuilder都继承自AbstractStringBuilder类
AbstractStringBuilder中也是使用字符数组来保存字符串,但其是可变类
StringBuilder和StringBuffer是Java中用于处理可变字符序列的类 允许通过追加、插入和删除等操作来修改字符串内容 而无需创建新的字符串对象
注意:虽然StringBuilder和StringBuffer是可变的 但它们并不是在”原本的字符串“上进行修改
当我们使用StringBuilder和StringBuffer的append、insert等方法时 只是在其内部维护的字符数组上执行操作(不是原本的字符串上修改)
我们这里只举例StringBuffer 因为StringBuilder和其几乎一致
StringBuffer的使用
1.创建StringBuffer对象
//使用无参构造方法创建一个空的StringBuffer对象
StringBuffer sb = new StringBuffer();
//指定初始容量来创建StringBuffer对象
int initialCapacity = 10; // 初始容量设为10
StringBuffer sb = new StringBuffer(initialCapacity);
//使用已有的字符序列创建
String str = "Hello, World!";
StringBuffer sb = new StringBuffer(str);
//使用字符数组创建
char[] charArray = {'H', 'e', 'l', 'l', 'o'};
StringBuffer sb = new StringBuffer(charArray);
//使用字符数组的子序列创建
char[] charArray = {'J', 'a', 'v', 'a', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm'};
// 从索引2(包含)开始,截取长度为5的子序列
StringBuffer sb = new StringBuffer(charArray, 2, 5); // 结果为"va Pr"
常用方法
·append(String s):将指定的字符序列追加到此字符序列的末尾
·insert(int offset,String s):将指定字符序列插入此序列中指定的offset位置
·delete(int start,int end):移除此序列的子字符串
·replace(int start,int end,String str):用给定String中的字符替换此序列的子字符串
·reverse():将此字符序列用其反转形式替换
·length():返回此字符序列的长度
·toString():生成此序列的字符串表达形式 --即将StringBuffer变为String
示例:
注意事项:
·在单线程环境下 如果不需要线程安全 推荐使用StringBuilder 因为它比StringBuffer有更好的性能
·StringBuffer的操作(如append、insert等)会返回StringBuffer对象本身 这允许链式调用
·当你需要频繁修改字符串时 使用StringBuilder或StringBuilder而不是String 因为String的每次修改都会创建一个新的字符串对象 这可能导致性能问题
题目案例:https://leetcode.cn/problems/backspace-string-compare/description/
当然本题还有很多其他的方法 在这里我们使用StringBuffer来解决该题
StringBuilder和StringBuffer的区别
1.线程安全性
StringBuffer:是线程安全的 它的所有公开方法都被synchronized修饰,这意呀着在多线程环境下,多个线程可以同时访问和修改同一个StringBuffer实例,而不会导致数据不一致的问题。
StringBuilder:不是线程安全的 它没有对方法进行同步处理,因此在多线程环境下,如果多个线程同时访问和修改同一个StringBuilder实例,可能会导致数据不一致的问题。
2. 性能
StringBuffer:由于所有方法都是同步的,因此在单线程环境下,其性能通常低于StringBuilder。同步机制虽然保证了线程安全,但也引入了额外的性能开销。
StringBuilder:没有同步机制,因此在单线程环境下,其性能通常优于StringBuffer。它更适合用于频繁修改字符串的场景。
3. 使用场景
StringBuffer:适用于需要线程安全的场景,如多线程环境下对字符串进行修改。
StringBuilder:适用于单线程环境,当不需要线程安全且追求更好的性能时,选择StringBuilder更为合适。
4. 缓冲区与toString方法
StringBuffer:在调用toString方法时,会直接使用缓存区的toStringCache值(如果存在)来构造一个字符串,这有助于优化性能。但需要注意的是,这个toString方法仍然是同步的。
StringBuilder:每次调用toString方法时,都需要复制一次字符数组,再构造一个字符串。这导致在频繁调用toString方法的场景下,StringBuilder的性能可能不如StringBuffer(尽管在大多数情况下,性能差异并不显著,因为toString方法的调用频率通常较低)。
5. 方法和API
StringBuffer和StringBuilder的大部分API是相同的,都提供了追加、插入、删除、替换等字符串操作方法。然而,由于StringBuffer是线程安全的,因此它的某些方法可能会比StringBuilder的方法稍慢一些,因为它们需要处理额外的同步逻辑。
综上所述,StringBuffer和StringBuilder在功能和用法上非常相似,但在线程安全性和性能方面存在显著差异。在选择使用哪一个类时,应根据具体的应用场景和需求来决定
总结
1.字符数组的可变性:StringBuffer 和 StringBuilder 内部使用的是一个可变的字符数组(尽管是私有的,外部不能直接访问)。这意味着它们可以在不需要创建新对象的情况下修改字符串内容。
2.字符串的不可变性:相比之下,String 对象在Java中是不可变的。一旦一个 String 对象被创建,它就不能被修改(即你不能改变它包含的字符序列)。如果你需要修改一个字符串,你必须创建一个新的 String 对象。
3.性能优势:由于 StringBuffer 和 StringBuilder 可以在不创建新对象的情况下修改内容,因此在需要频繁修改字符串的场合(如在循环中构建大型字符串),它们比使用 String 拼接(如使用 + 运算符或 concat 方法)要高效得多。因为每次使用 + 或 concat 进行字符串拼接时,都会创建一个新的 String 对象。
4.线程安全性:StringBuffer 是线程安全的,而 StringBuilder 不是。这意味着在多线程环境中,你应该使用 StringBuffer(但如果你确定只有一个线程会访问 StringBuilder 对象,那么使用 StringBuilder 会获得更好的性能)。
5.构造字符串:虽然 StringBuffer 和 StringBuilder 不需要为了修改内容而构造新的字符串对象,但如果你需要将它们的内容转换为 String 对象(例如,为了打印或将其传递给接受 String 参数的方法),则需要进行一次转换。这个转换操作会创建一个新的 String 对象,但这个过程是高效的,因为它只需要复制内部字符数组的内容(而不需要像使用 + 那样进行多次复制和拼接)