为什么String设计成不可变的
1.字符串常量池的需要,提升效率和减少内存分配
2.安全性考虑,防止被意外修改(HashSet中存的值如果是可变的String,则破坏了唯一性;不可被写所以线程安全;)
3.作为HashMap、HashTable等hash型数据key的必要。因为不可变的设计,jvm底层很容易在缓存String对象的时候缓存其hashcode,这样在执行效率上会大大提升。
为什么String对象是不可变的?
看以下代码:
String s = "abcdef";
s="123456"
System.out.print(s);
此时输出s:s="123456" 从打印结果可以看出,s的值确实改变了。大家可能以为那怎么还说String对象是不可变的呢? 其实这里存在一个误区: s只是一个String对象的引用,并不是对象本身。s这个引用从"abcdef",指向了"123456",对象本身一直是存在的。
首先来看String类中的成员变量
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</string>
以上代码可以看出来String类就是对字符数组的封装,hash成员变量是该String对象的哈希值的缓存。
在Java中,数组也是对象,所以value成员变量也是一个引用,它指向一个真正的数组对象。
由上面代码看出,value[]这个成员变量是final修饰的,也就是说在String类内部这个值初始化后就不能被修改,String对象就是不可变的。
String中在存在一些其他方法,截取,替换等,都是创建新的对象。
以下是关于字符串比较的解析
String s1 = "abc";
String s2 = "a"+"b"+"c";
System.out.print(s1==s2);//true
String s3 = new String("abc");//只要有关键字new,一定是开辟了新的空间
String s4 = "a"+"bc";
System.out.print(s4==s2);//true 常量+常量 javac会进行优化,会自动编译变成abc
String s5="bc";
String s6="a"+s5
System.out.print(s6==s4); // false 常量与变量的运算,javac不进行任何优化,再执行得时候使用关键字new创建一个新的对象
注意:String s3 = new String("abc");这句代码分两种情况:如果常量池种没有,回先在常量池中放一份,再往堆中存放一份,创建2次对象;如果常量池中有,就直接创建一次对象;
网友评论