目录
1.String为什么是不可变得?
1.1 “不可变”的概念?
1.2 怎么实现的?
1.2.1 为什么String类被final修饰?
1.2.2 为什么char value[] 被final修饰?
2.优点?
最近在研究String,发现有些概念自己搞了很久才搞懂,为了方便有后来者学习,也为了让自己加深一下记忆。在此记录一下,如有错误,还请多多指正。
1.String为什么是不可变得?
1.1 “不可变”的概念?
这里不可变指的是String指向字符串常量池中的常量是不可变得,但是可以改变引用的地址。并不是指Sting本身被赋值后就不能再改变了。
当String a 被重新赋值时,不是修改常量池中的值,也就是“abcd”是不可修改的,可以开辟另外一个空间“abcdef”,改变Sting a的引用地址。
1.2 怎么实现的?
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
首先我们了解一下final的作用
- final修饰的类,不能被继承。
- final修饰的方法,不能被重写。
- final修饰的变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的,也就是说在对其初始化之后便不能再让其指向另一个对象。。
1.2.1 为什么String类被final修饰?
String类被final修饰目的是:确保它们不会在子类中改变语义。String类是final类,这意味着不允许任何人定义String的子类。就是为了防止大家乱继承String,从而改变String的特性,这样就会打破成为共识的基本约定。
1.2.2 为什么char value[] 被final修饰?
目的:保证String不变性。(这样才能实现字符串常量池)
问题:被final修饰一定能保证value[]的不变性吗?
答案:不能
看如下代码:
@Test
public void finalTest02() {
final char[] value = {'c', 'c', 'c'};
System.out.println(value);
//将索引位置为2的修改为b
value[2] = 'a';
System.out.println(value);
}
/**
* 结果
* ccc
* cca
*/
@Test
public void finalTest(){
final char[] value = {'a','a','a'};
char[] value2 = {'b','b','b'};
value = value2;
//此时会报错,证明被final修饰不能value不能被重新赋值。
}
我们通过这段代码可以看出,仅仅被final修饰是不能保证Sting的不变性的。
真正保证String不变性的是
- private 关键字可以保证value不被其他类访问和修改。
- String 类没有提供修改这个字符串的方法。
2.优点?
- 作为在java中经常被使用和访问的类,保证String的不变性可以实现字符串常量池(在jvm方法区中),不用频繁的创建对象,可以节省内存空间。
- 因为String是不可变的,多线程对同一个String操作时,不用考虑安全性的问题。因为是线程安全的。
- String很适合做Map的key。因为String有个成员变量hash
/** Cache the hash code for the string */
private int hash; // Default to 0
保存的是 String 对象的 HashCode。因为 String 是不可变的,所以对象一旦被创建之后,HashCode 的值也就不可能变化了,我们就可以把 HashCode 缓存起来。这样的话,以后每次想要用到 HashCode 的时候,不需要重新计算,直接返回缓存过的 hash 的值就可以了,因为它不会变,这样可以提高效率,所以这就使得字符串非常适合用作 HashMap 的 key。