【源码解析】Java8-String
- #### String是Immutable(不可变的)
String源码及分析:
类定义:
1
public final class String {}
变量定义:
1
2
3
4
5
6
7/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0hashCode计算:
1
2
3
4
5
6
7
8
9
10
11
12public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}由源码可以看出hash值初始化时是0,当获取过一次之后hashCode就会被计算出来,然后被缓存了下来,随String一块不再变了,也正是因为此,喜欢吧String作为HashMap的key
hashCode计算有个问题:为什么需要一个中间变量h ?
答:没有临时变量是线程不安全的,因为多线程访问下,如果没有h,当一个线程进行计算时,第二个线程进来,此时hash不为0则直接返回此时错误的值。
String保持不可变性采取了哪些措施?
- value[] 使用 private final 修饰
- 构造函数中复制实参的值给 value[]
- 不对外提供任何修改 value[] 值的方法
- 需要返回 String 的方法,绝不返回原对象,都是重新 new 一个 String 返回
String对象的创建
String Pool(字符串池):
定义:Java为String提供了特殊的存储机制,叫String intern pool,全局共享的,存储的是队中字符串实例的引用而不是存储实例本身,在方法区
哪些对象会放在:1.字面值字符串 2.字符串赋值常量表达式3.使用intern方法对String对象操作返回的String对象
举栗子:
1
2
3
4
5
6String st1 = "yveshe1";
String st2 = new String("yveshe2");
String st3 = "a"+"b";
String st = st1 + "hello";
String internStr = st.intern();
System.out.println(st == internStr);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
1. 字面值字符串有:yveshe2,hello,a,b
2. 字符串赋值表达式:st1 = "yveshe1" ,st3 = "a"+"b";
3. 使用intern方法的有:st1 = yveshe1hello
其中st1在常量池 ,st2不在常量池 ,st3在常量池,st不在常量池
internStr1.6之前在常量池,1.6之后使用的st的实际地址,只在常量池中保存了引用
String对象的创建:
1. String s1 = "aaaa";
Java虚拟机首先在字符串池中查找是否存在值为”aaaa“这个对象,如果有则不再创建新的对象,直接返回已存在的对象的引用;如果没有则先创建这个对象,放在字符串池中,再将它引用返回
2. String s1 = new String("aaaa");
创建了两个对象,一个是字面量aaaa创建的String对象,在String Pool中,另外一个是new产生的String对象,在Java Heap中
3. 使用+操作符号创建String对象
- String s1 = "yves" + "he";
System.out.println(s1 == "yveshe");
编译会变成String s1 = "yveshe"
- String s1 = "yves";
String s2 = s1 + "he";
System.out.println(s2 == "yveshe");
编译成如下:
String s1 = "yves";
String s2 = (new StringBuilder(String.valueOf(s1))).append("he").toString();
System.out.println(s2 == "yveshe");
4. intern()方法的用途
String s = new String("YvesHe").intern();
System.out.println(s == "YvesHe");
结果为true
作用有两个,1. 把字符串字面量放入常量池 2. 返回常量的引用
5. String.ValueOf和Integer.toString和“”+i
前两个没啥区别,最后会new 一个String
参考:https://juejin.im/post/5ca5c51451882544114cdc95