String、StringBuffer 和 StringBuilder
String 是 Java 中使用最广泛的类之一。StringBuffer 和 StringBuilder 类提供了操作字符串的方法。我们将研究 StringBuffer 和 StringBuilder 之间的区别。StringBuffer 与 StringBuilder 是一个常见的 Java 面试问题。
String、StringBuffer 和 StringBuilder
字符串是核心 Java 面试中最重要的主题之一。如果您正在编写一个在控制台上打印某些内容的程序,则您正在使用 String。本教程旨在重点介绍 String 类的主要功能。然后我们将比较 StringBuffer 和 StringBuilder 类。
Java 中的字符串
-
String类代表字符串,我们可以通过两种方式实例化String。
String str = "ABC"; // or String str = new String("ABC");
-
String 在 Java 中是不可变的。因此它适合在多线程环境中使用。我们可以在函数之间共享它,因为不用担心数据不一致。
-
当我们使用双引号创建字符串时,JVM 首先在字符串池中查找具有相同值的字符串。 如果找到,它将从池中返回字符串对象的引用。 否则,它在字符串池中创建字符串对象并返回引用。 JVM 通过在不同的线程中使用相同的字符串节省了大量内存。
-
如果使用 new 运算符创建字符串,则会在堆内存中创建。
-
+ 运算符对于 String 来说是重载的。我们可以使用它来连接两个字符串。尽管在内部它使用 StringBuffer 来执行此操作。
-
String 重写了equals() 和 hashCode()方法。两个字符串只有具有相同的字符序列才相等。equals() 方法区分大小写。如果您需要不区分大小写的检查,则应使用 equalsIgnoreCase() 方法。
-
该字符串使用 UTF-16 编码作为字符流。
-
String 是一个 final 类。除“private int hash”外,所有字段都是 final。此字段包含 hashCode() 函数值。仅在第一次调用 hashCode() 方法时计算 hashcode 值,然后缓存在此字段中。此外,哈希是使用 String 类的 final 字段通过一些计算生成的。因此,每次调用 hashCode() 方法时,都会产生相同的输出。对于调用者来说,似乎每次都在进行计算,但在内部,它缓存在哈希字段中。
String 与 StringBuffer
由于 String 在 Java 中是不可变的,因此每当我们执行字符串操作(如连接、子字符串等)时,它都会生成一个新的字符串并丢弃旧的字符串以进行垃圾收集。这些是繁重的操作,会在堆中产生大量垃圾。因此,Java 提供了用于字符串操作的 StringBuffer 和 StringBuilder 类。StringBuffer 和 StringBuilder 是 Java 中的可变对象。它们为字符串操作提供了 append()、insert()、delete() 和 substring() 方法。
StringBuffer 与 StringBuilder
直到 Java 1.4,StringBuffer 都是字符串操作的唯一选择。但是,它有一个缺点,即其所有公共方法都是同步的。StringBuffer 提供线程安全性,但性能会受到影响。在大多数情况下,我们不会在多线程环境中使用 String。因此,Java 1.5 引入了一个新类 StringBuilder,它与 StringBuffer 类似,只是线程安全性和同步性有所区别。StringBuffer 有一些额外的方法,例如 substring、length、capacity、trimToSize 等。但是,这些方法并不是必需的,因为 String 中也存在所有这些方法。这就是为什么这些方法从未在 StringBuilder 类中实现的原因。StringBuffer 是在 Java 1.0 中引入的,而 StringBuilder 类是在 Java 1.5 中引入的,因为考虑到了 StringBuffer 的缺点。如果您处于单线程环境中或不关心线程安全性,则应使用 StringBuilder。否则,请使用 StringBuffer 进行线程安全操作。
StringBuilder 与 StringBuffer 性能
我正在尝试检查由于与append()
多次对 StringBuffer 和 StringBuilder 对象执行的示例程序进行同步而对性能产生的影响。
package com.journaldev.java;
import java.util.GregorianCalendar;
public class TestString {
public static void main(String[] args) {
System.gc();
long start=new GregorianCalendar().getTimeInMillis();
long startMemory=Runtime.getRuntime().freeMemory();
StringBuffer sb = new StringBuffer();
//StringBuilder sb = new StringBuilder();
for(int i = 0; i<10000000; i++){
sb.append(":").append(i);
}
long end=new GregorianCalendar().getTimeInMillis();
long endMemory=Runtime.getRuntime().freeMemory();
System.out.println("Time Taken:"+(end-start));
System.out.println("Memory used:"+(startMemory-endMemory));
}
}
我还对 StringBuffer 对象运行了相同的代码,以检查时间和内存值。我对每种情况都执行了 5 次代码,然后计算了平均值。
i 的值 | StringBuffer(时间,内存) | StringBuilder(时间,内存) |
---|---|---|
10,00,000 | 808,149356704 | 633,149356704 |
1,00,00,000 | 7448, 147783888 | 6179, 147783888 |
很明显,即使在单线程环境下,StringBuilder 的性能也优于 StringBuffer。这种性能差异可能是由 StringBuffer 方法中的同步引起的。
String、StringBuffer 和 StringBuilder
- String 是不可变的,而 StringBuffer 和 StringBuilder 是可变类。
- StringBuffer 是线程安全且同步的,而 StringBuilder 不是。这就是 StringBuilder 比 StringBuffer 更快的原因。
- 字符串连接运算符 (+) 在内部使用 StringBuffer 或 StringBuilder 类。
- 对于非多线程环境中的字符串操作,我们应该使用 StringBuilder,否则使用 StringBuffer 类。
以上就是 String、StringBuffer 和 StringBuilder 之间的区别的简要概述。在大多数常规编程场景中,StringBuilder 比 StringBuffer 更合适。参考文献: