你在面试时,面试官让你讲讲String String Buffer String Builder的区别,你是否能流畅的、完整的叙述出他们三者的区别?
✍先说结论
- 相同点: 他们的底层都是由char数组实现的。
- 不同点:
- String对象一旦创建,是不能修改的,如果要修改,会重新开辟空间来存储修改后的对象;而String Buffer和String Builder创建的对象是可以修改的。
- String Buffer是线程安全的,他几乎所有方法都被synchronization 所修饰,允许采用多线程的方式执行添加或删除字符的操作,但是效率比较低;而String Builder是单线程的。如果所有字符串在一个单线程中编辑(通常都是这样),则应该使用String Builder。这两个类的API大部分是相同的。
总结
- 当在程序中需要频繁的更改字符串的内容时,不要使用String(会浪费大量的空间)
- 如果是要考虑线程下的安全问题时,使用StringBuffer
- 否则使用String Builder
✍String类
String的三种构造方法
public static void main(String[] args) {
// 使用常量串构造
String s1 = "hello bit";
System.out.println(s1);
// 直接newString对象
String s2 = new String("hello bit");
System.out.println(s1);
// 使用字符数组进行构造
char[] array = {'h','e','l','l','o','b','i','t'};
String s3 = new String(array);
System.out.println(s1);
}
我们要理解String类,首先要搞清楚String的底层
通过源码可以看出
String是一个引用类型
我们举几个实际的例子
来更清楚的了解String的本质
请你先判断这个表达式的结果是什么
答案为true
我们画图来理解
再判断一下这个表达式的值是什么
结果为false
✍字符串的不可变性
- String类被final修饰,表明该类不能被继承
- value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。
✍为什么String要设置成不可变类型
- 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
- 不可变对象是线程安全的.
- 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中
易错点
- Java中有常量优化机制,“Hello"和"World"本身就是字符串常量,所以在编译时,会直接把"Hello"和"World"合并成"HelloWorld"字符串,又因为在执行s3的时候已经在常量池中创建了"HelloWorld".
- 当变量与字面量或变量与变量进行拼接时,会在堆中创建一个StringBuilde对象,然后使用StringBuilder的append()方法将变量与字面量或变量与变量进行拼接,最后调用toString()方法转成String对象。所以s5、s6、s7指向的都是堆内存中String对象的地址值。
public static void main(String[] args) {
final String s1="Hello";
String s2="HelloWorld";
String s3=s1+"World";
System.out.println(s2==s3); //true
}
被final修饰表示是一个常量,所以此时s1+“World"就相当于"Hello”+“World”,结果仍然是一个常量。
有人说:字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变。
这种说法是错误的,不是因为String类自身,或者其内部value被final修饰而不能被修改。
final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。
所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
以上就是本文所有内容,如果对你有帮助的话,点赞收藏支持一下吧!💞💞💞