一、概述
字符串的缓存 intern 方法,从永生代移到了堆中,由char[] 变为了 byte[] 减少了内存的使用空间。为了避免在系统中创建大量的对象,由此引入了字符串常量池。
二、运行机制
创建一个字符串时,会先从字符串常量池中寻找相同的字符串,如果有不需要创建对象,直接返回对象引用;如果没有需要创建字符串对象,放入常量池中,返回对象引用, new String 的字符串时 存放在 堆中的,不检查字符串常量池。
String str1 = "123"; //通过直接量赋值方式,放入字符串常量池
String str2 = new String(“123”);//通过new方式赋值方式,不放入字符串常量池
三、StringBuilder 和StringBuffer
都是继承了 AbstractStringBuilder,具有统一的调用接口,底层是 有序的字符序列(char类型的数组)和 ArrayList 的 底层很相似,超过了默认的大小后,需要扩容,把原来的数据复制到新的数组中,提前预知数量可以减少内存复制的操作,减少内存的消耗
1.StringBuilder 是 线程不安全的
2.StringBuffer 是线程安全的 append中 加了 关键 synchronized
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
四、 使用`+`拼接字符问题
//使用 + 拼接
String wechat = "Hollis";
String introduce = "测试文章";
String hollis = wechat + "," + introduce;
//使用 concat 拼接
String yc = "yangchong";
String introduce = "潇湘剑雨";
String hollis = yc.concat(",").concat(introduce);
String str1 = "111111";
String str2 = "222222";
String str = str1 + str2;
System.out.println(str);
等同于
String str1 = "111111";
String str2 = "222222";
StringBuilder sb = new StringBuilder();
sb.append(str1);
sb.append(str2);
String str = sb.toString();
System.out.println(str);String str1 = null;
String str2 = "222222";
String str = str1 + str2;
System.out.println(str);
String str1 = null;
StringBuilder sb = new StringBuilder();
sb.append(str1 ); // null拼接会变成字符串"null"
源码分析:public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
//AbstractStringBuilder类中append方法
@Override
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
return appendNull();
if (s instanceof String)
return this.append((String)s);
if (s instanceof AbstractStringBuilder)
return this.append((AbstractStringBuilder)s);return this.append(s, 0, s.length());
}private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
五、String深入分析
1.由于 String 类,属性都是 final 的,所以在 字符串拼接的时候,会产生多个String 对象
2.为什么将缓存放进到 堆中呢?
a: 避免了永久代被占满的问题,JDK1.8之后,永久代被元数据区(MetaSpace)所替代
3.String不可变的好处?
a:因为 String 的不可变性,所以String的hash 经常被使用, hashmap 的key的得到hash值,右移16位,和高位异或,得到唯一的不重复的hash 值,
b:因为String 的不可变性,所以才能使用字符串常量池。
c:线程安全,可以在多个线程使用。