不可变性
- String 的底层实现是依靠 char[] 数组,但是用了final修饰,隔绝了使用者对 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为不可变的,每次String对象做累加时都会创建StringBuilder对象。
intern()
new String都是在堆上创建字符串对象。当调用 intern() 方法时,编译器会将字符串添加到常量池中(stringTable维护),并返回指向该常量的引用。
通过字面量赋值创建字符串(如:String str=”twm”)时,会先在常量池中查找是否存在相同的字符串,若存在,则将栈中的引用直接指向该字符串;若不存在,则在常量池中生成一个字符串,再将栈中的引用指向该字符串。
“+”操作或final string也是进入常量池
常量字符串和变量拼接时(如:String str3=baseStr + “01”;)会调用stringBuilder.append()在堆上创建新的对象。
JDK 1.7后,intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。
StringBuffer vs StringBuilder
String , StringBuffer 与 StringBuilder之间有什么区别吗?
性能方面: StringBuilder > StringBuffer > String(+)(for循环里面字符串拼接)
线程安全: StringBuilder (非线程安全,速度快),StringBuffer (线程安全,速度慢)
如何选择: StringBuilder (方法内,无线程安全问题),StringBuffer (有线程安全问题,使用它)
3点建议
- 当你连接 2 或 3 个String时,使用String.concat()。
- 如果你要连接多于3个String(不含3),并且你能够精确预测出最终结果的长度,使用StringBuilder/StringBuffer,并设定初始化容量。
- 如果你要连接多于3个String(不含3),并且你不能够精确预测出最终结果的长度,使用StringBundler。
StringBuffer 为什么是线程安全的呢?
//StringBuffer源码
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
@Override
public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,int dstBegin){
super.getChars(srcBegin, srcEnd, dst, dstBegin);
}
equals() VS == VS
- ==是判断两个对象的内存地址是否相同
- equals()原始调用的是==,但是对于string类需要重写,使之按照内容判断
- 重写equals()后一定要重写hashcode(),因为hashcode相等属于equals相等的范畴。
- 参考:Java提高篇——equals()与hashCode()方法详解