目录
一、字符串的不可变性
二、字符串的修改
三、StringBuilder和StringBuffer
四、面试题
一、字符串的不可变性
1. 如上图所示,String类的是被final修饰的类(不能被继承),成员变量value值是一个被final修饰的字节型数组。
2. 以下图代码为例,字符串的不可变性在讲某字符串变量被重新赋值新的字符串常量值时,并不是将原本的字符串修改成了新的字符串,而是会在常量池中查找是否有"hello"对象,如果有仍然使str引用指向字符串常量池中的“hello”对象,如果没有则会在字符串常量池中创建一个新的对象,然后让str引用指向这个新的对象。
3. 为什么不直接修改常量池中“hello”对象的value值呢,反而要采用创建新对象的方式?
答:① 首先我们得了解一下被final修饰的数组意味着什么。
没被final修饰前的数组引用:
被final修饰后的数组引用:下图中当数组被final修饰后array引用的值不能够被修改了(array引用不能指向一个新的数组对象),但数组每个元素的内容是可变的。
② 依照第①点得出的结论,也就是说我们不可以更改value引用的值,但是可以更改value数组每个元素的内容。此时有人就会说,那我们直接去更改value数组每个元素的内容就好了呀。但是观察String类的原码可以发现,成员变量value被private修饰了,且编译器并没有提供getter 和 setter方法,private这个修饰符也是无法被修改的,也就是说我们没办法拿到value引用所指向的对象,通过数组名[]去更改value数组中的值,更不可能去更改value引用的值,综上str="world"类似的赋值,编译器并没有采用改常量池中“hello”对象的value值,反而是采用了创建新对象的方式。
4. 纠正:有些人说:字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变。 这种说法是错误的,不是因为String类自身,或者其内部value被final修饰而不能被修改。 final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。字符串的不可变是因为其内部保存字符的数组被private final修饰,且String类中没有提供getter 和 setter方法,private这个修饰符也无法被修改使得我们无法修改value引用的值 和 value引用所指向对象的值所导致的。
补充:Java中可以通过一种叫反射的机制来获取到被封装的字段,在数组结构的最后会讲到,埋坑🕳。
5. 为什么 String 要设计成不可变的?(不可变对象的好处是什么?) (选学)
①. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
②. 不可变对象是线程安全的.
③. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中.
二、字符串的修改
1. 依据字符串的不可变形,也就是说下图代码并不属于对字符串本身进行修改。
2. 上述代码的底层等效代码:
也就是说如果我么写出了一个这样的代码:
在代码的底层每次拼接都会new 一个StringBuilder对象,调用stringBuilder.append()方法,这样的代码非常耗费资源。修改代码(使用StringBuilder实现字符串的拼接):
3. 注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
① String变为StringBuilder: 利用StringBuilder的构造方法或append()方法。
② StringBuilder变为String: 调用toString()方法。
4. 总之,尽量避免对String的直接修改或拼接,因为在这过程中会额外创建很多的对象消耗资源,因此如果某字符串变量在使用过程中会进行修改或拼接操作建议尽量使用StringBuffer类或者StringBuilder类。
三、StringBuilder和StringBuffer
1. StringBuilder和StringBuffer类的常见使用方式是一样的:
2. 对StringBuilder和StringBuffer对象的修改/拼接都是在对象本身进行修改/拼接 (和String类相反)
3. StringBuilder和StringBuffer的区别: 单线程用StringBuilder, 多线程用StringBuffer。
四、面试题
1. String、StringBuffer、StringBuilder的区别?
① String和StringBuffer、StringBuilder相比,String的内容不可修改,而StringBuffer、StringBuilder的内容可修改,且含有一些String没有的方法。
② StringBuffer、StringBuilder这两个类大部分功能是相同的,区别在于StringBuffer被synchronized修饰r采用同步处理,属于线程安全操作,通常在多线程中会使用到,而StringBuilder未采用同步处理,属于线程不安全操作。
2. 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】(答案:8个)
String str = new String("ab"); // 会创建2个对象
String str = new String("a") + new String("b"); // 会创建6个对象(注意:调用toString方法,toString方法底层也会new一个对象)
本篇已完结 ......