1.String StringBuffer StringBuilder
String的创建
当我们使用双引号创建一个字符串时,如下,JVM 首先在字符串池中寻找具有相同值的字符串。
String str1 = "ABC";
如果找到了,它将返回字符串池中的字符串对象的引用。否则,它会在字符串池中创建字符串对象并返回引用。JVM 通过在不同的线程中使用相同的字符串,节省了大量的内存。
如果使用 new 运算符创建字符串,则会在堆中创建它。
String源码
/** 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的几个特殊方法
public 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;
}
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
注意:hash码相同,这两个对象不一定相同,但这两个对象如果相同,则hash码一定相同。
所以hash码一个很重要的作用是保证对象在放入HashMap时相同的对象要放入同一个桶。
其实Java内置的数据类型的包装对象都重写了hashcode和equals方法,当我们使用HashMap时,如果我们要让对象具有不可重复性,其实我们看过HashCode源码都知道,里面的hash算法就是在你对象的hash码的基础上进行扩散,所以是需要你的对象里里面是有hashcode方法的。不然对象放入hashmap会直接按照引用地址来判别。
示例
class MyBean {
int x;
String s;
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof MyBean)) return false;
if(((MyBean)obj).x == x) return true;
return false;
}
@Override
public int hashCode() {
return (s!=null?s.hashCode():1)*31+x;
}
}
StringBuilder和StringBuffer
由于 String 在 Java 中是不可变的,因此每当我们执行字符串拼接操作时,它都会生成一个新的 String 并丢弃旧的 String 以进行垃圾收集。
这些重复的操作会在堆中产生大量垃圾冗余。所以 Java 提供了 StringBuffer 和 StringBuilder 类,应该用于字符串操作。
StringBuffer 和 StringBuilder 是 Java 中的可变对象。
StringBuffer | StringBuilder |
---|---|
线程安全 | 非线程安全 |
同步 | 非同步 |
始于 Java 1.0 | 始于 Java 1.5 |
慢 | 快 |
StringBuffer
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
底层的数组不再是final修饰的了
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
方法都加了synchronized修饰,所以都是同步的
StringBuilder
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
没用同步,所以线程不安全。
ringBuilder
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
没用同步,所以线程不安全。
String类型的相加就是通过StirngBuilder实现