Java String的存储
String的存储
原理
① Java 将字符串常量实现为 String 对象,编译时期能够确定的字符串常量存储在常量区中:
String a = "12345"; // 编译时期在常量池创建 “123456”,运行时将引用赋值给a
String b = a; // 运行时将a的引用赋值给b
② 运行时才能确定的字符串常量是在堆中创建的:
// 编译时将在常量池创建两个 String 对象 "12345" 和 "67"
String a = "12345";
String a = a.concat("67"); // 运行时在堆中创建 ”1234567“,并将引用赋值给a
String b = new String("1234567"); // 运行时在堆中创建 ”1234567“,并将引用赋值给b
③ 编译时能够合并的字符串常量将会合并、并在常量区中创建,带变量的将无法合并,将在堆中创建:
String a = "12" + "34"; // 编译时在常量区创建 "1234",运行时将引用赋值给a
String b = "";
String c = "67" + b + "89"; // 编译时将在常量区创建 "67" 和 "89",运行时在堆中创建 "6789",并将引用赋值给 c
举例
String a = "a";
String b = "b";
String c = "a";
String ab1 = a + b;
String ab2 = "ab";
String ab3 = a.concat(b);
String ab4 = a + b;
String ab5 = "a" + "b";
System.out.println(a == c); // true
System.out.println(ab1 == ab2); // false;
System.out.println(ab1 == ab3); // false;
System.out.println(ab1 == ab4); // false;
System.out.println(ab1 == ab5); // false;
System.out.println(ab2 == ab3); // false;
System.out.println(ab2 == ab4); // false;
System.out.println(ab2 == ab5); // true;
System.out.println(ab3 == ab4); // false;
System.out.println(ab3 == ab5); // false;
System.out.println(ab4 == ab5); // false;
Intern() 方法
原理
① 对某个 String 变量调用 .intern()
方法:
- 如果常量池中不存在这个字符串,则:并返回常量池中该子串引用
- JDK1.6:将字符串构建的对象加入常量池
- JDK1.7+:将这个对象的引用加入常量池
② 当某个字符串需要被重复使用时,可以考虑使用 inter()
,节省大量重复字符串对象消耗的堆内存(像上一节的举例一样,ab1
、ab3
和 ab4
的内容一样,但是却占用了不同的堆内存)
注意:后边的举例都以 JDK1.7+ 作为默认环境
举例
例一
(1)String str = new String("abc");
创建了几个对象?
答:常量池有 “abc” 的话就创建了一个对象,常量池没有 “abc” 的话就创建了两个对象
(2)String str = "abc";
创建了几个对象?
答:常量池有 “abc” 的话就创建了零个对象,常量池没有 “abc” 的话就创建了一个对象
(3)new String("abc").intern();
创建了几个对象?
答:常量池有 “abc” 的话就创建了一个对象,常量池没有 “abc” 的话就创建了两个对象
例二
String b = new String("ab" + "cd");
String c = b.intern();
System.out.println(c == b); // false
由于 "ab" + "cd"
可以合并,因此常量区中刚开始就有 "abcd"
,b.intern()
没有做什么动作;
String a == "";
String b = new String("ab" + a + "cd");
String c = b.intern();
System.out.println(c == b); // true
由于 "ab" + a + "cd"
无法合并,因此常量区中刚开始没有 "abcd"
,而是在调用了 b.intern()
之后才有,所以 c
指向的也是堆中的 "abcd"
例三
String d = "";
String b = new String("ab" + "cd");
String a = "a" + d + "b";
System.out.println(a == a.intern()); // true
因为 "ab" + "cd"
可以合并,因此常量区中刚开始没有 "ab"
,是在 a.intern()
之后才有的,所以 a
和 a.intern()
指向的是同一个对象
String d = "";
String b = new String("ab" + d + "cd");
String a = "a" + d + "b";
System.out.println(a == a.intern()); // false
因为 "ab" + "cd"
不能合并,因此常量区中刚开始就有 "ab"
, a.intern()
没有做什么动作;所以 a.intern()
指的是原来常量区中的 "ab"
总结
没啥好总结的hhhh,有点绕,但是把上面的举的例子都理解了就问题不大