Java源码分析String为什么是不可变的?
- 不可变:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。
- 不能改变状态:指的是不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,并且引用类型指向的对象的状态也不能改变。
1. String类源码分析
通过String类源码可知:String底层是由char数组构成,当创建一个字符串对象时,实质是将字符串保存在char数组中,因为数组是引用对象,为了防止数组可变,JDK加了final修饰,因为final修饰的数组也只是代表了引用不可变,不能代表数组内容不可变,因此对JDK又加了private修饰符。
有了final和private的修饰和底层的实现,保证了String的引用和内容都是不可变的!
JDK1.7版本源码如下:
public final class String
implements Serializable, Comparable, CharSequence
{
public String()
{
hash32 = 0;
value = new char[0];
}
public String(String s)
{
hash32 = 0;
value = s.value;
hash = s.hash;
}
public String(char ac[])
{
hash32 = 0;
value = Arrays.copyOf(ac, ac.length);
}
//value比较特殊,因为他是一个引用变量,而不是真正的对象。value是final修饰的,也就是说final不能再指向其他数组对象。private的私有访问权限的作用都比final大。
private final char value[];
private int hash;
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField serialPersistentFields[] = new ObjectStreamField[0];
public static final Comparator CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
private static final int HASHING_SEED;
private transient int hash32;
······
}
2. 不可变的好处
1、多线程下安全性
String是不可变的,因此多线程操作下,它是安全的。
试想一下如下代码,如果String是可变的,那么get方法内部改变了str的值,方法外部str也会随之改变。
public String get(String str){
str += "Hello World";
return str;
}
2、类加载中体现的安全性
类加载器要用到字符串,不可变提供了安全性,以便正确的类被加载。
3、使用常量池可以节省空间
String str1 = "Hello World";
String str2 = "Hello World";
像上面这样字符串str1 和str2 都用字面量"Hello World"赋值。str1 和str2它们其实都指向同一个存放内存"Hello World"字符串的地址。节省了内存空间,提了高效率。
……
帮助他人,快乐自己,最后,感谢您的阅读!
所以如有纰漏或者建议,还请读者朋友们在评论区不吝指出!
……
个人网站…知识是一种宝贵的资源和财富,益发掘,更益分享…