String为什么要设计成不可变
String为什么要设计成final的?
设计成不可变的好处:
-
允许string对象缓存hashCode
-
String 对象的哈希码被频繁的使用,所以不可变保证了哈希值的唯一性,不必每次都去计算哈希值,也是一种优化手段。
-
不可变保证了HashSet和HashMap的键值的唯一性,是其键不可重复成为可能。
-
访问的网络连接地址url,文件路径path,如果String 可变,会引起各种隐患。
-
-
支持线程安全
-
支持字符串常量池
- 在大量使用字符串的情况下,可以节省内存空间,提高效率;如果常量池中已存在,就直接使用常量池中的字符串。常量池的最基本条件就是字符串的不可变性。
String怎么样实现不可变?
String类的属性源码:
- 首先String类是final修饰的,不能被继承,方法就不会被随意重写;
- 字符串底层实际就是封装的字符数组,value属性被final修饰,则字符数组的引用就没办法修改;
- value属性是private修饰的,所以外界访问不到,同时String也没有提供setValue方法,所以字符串生成后不可变;
String类真的是一定不可变吗?我们使用反射就可以改变String的值,测试之后发现hashCode()值没变,但是打印的值确实变了,证明我们反射修改是成功的,但是我们平时不这样做。
代码入下:
public static void changeStringByReflection() {
String str = "Hello world";
// 获取str对象的value属性
Field valueOfStr = str.getDeclaredField("value");
// 修改value属性的访问权限为可访问
valueOfStr.setAccessible(true);
// 获取value值
char[] chr = (char[])valueOfStr.get("str");
// 修改值
chr[5] = '+';
System.out.println(str); // 输出:Hello+World;
}
为什么要设计字符串常量池,意义是什么?
字符串常量池有助于Java运行时节省大量空间,虽然创建字符串时需要更多的时间,耗费高昂的时间与空间代价。
也是享元模式的实例。
为了让数据不冲突进行共享。
jdk1.7及之后String类的intern()用法:
public static void main(String args[]) {
String s4 = new String("ab") + new String("cde");
String s5 = "abcde";
s4.intern();
// 此时由于s5的时候,字符串常量池中已经存在了abcde,所以s4.intern()的时候返回的是常量池中的引用
System.out.println(s4 == s5); // false
}
public static void main(String args[]) {
String s4 = new String("ab") + new String("cde");
s4.intern();
String s5 = "abcde";
// 由于s4.intern()方法调用之前,常量池中是没有abcde的,所以调用后常量池中是s4的引用,所以s5指向常 量池的时候,指向的是s4的引用
System.out.println(s4 == s5); // true
}
public static void main(String args[]) {
String s4 = new String("abcde");
s4.intern();
String s5 = "abcde";
System.out.println(s4 == s5);
}
// 结合上面两个例子,说明new String("abcde")的时候,如果常量池中不存在“abcde”,则会创建两个对象,首先再常量池创建“abcde”,然后再new堆空间中创建一个对象。
对于final修饰的字段,编译期直接进行了常量替换(而对于非final字段则是在运行期进行赋值处理的)。
final String str1=”ja”;
final String str2=”va”;
String str3=str1+str2;
在编译时,直接替换成了String str3=”ja”+”va”,再次替换成String str3=”java”原文链接:https://blog.csdn.net/soonfly/article/details/70147205
new string(abc)创建了几个对象
一个或两个,当常量池中没有abc的时候,创建了两个。
// 一下代码会创建几个对象
String str = "abc" + "def"; // 创建一个"abcdef"对象,编译的时候直接优化为常量"abcde"
String str = "abc" + new String("def"); // 创建了4个字符串对象,1个StringBuilder对象
创建一个"abcdef"对象,编译的时候直接优化为常量"abcde"
String str = “abc” + new String(“def”); // 创建了4个字符串对象,1个StringBuilder对象