这篇文章上讲解的知识点你全搞明白了,Java中的字符串你就彻底理解了。
字符数组的存储方式
public static void main(String[] args) {
char[] arr = new char[]{'1', '2'};
while (true);
}
字符串常量池
即String Pool,但是JVM中对应的类是StringTable,底层实现是一个hashtable,看代码
class StringTable : public Hashtable<oop, mtSymbol> {
……
Key的生成方式
1、通过String的内容+长度生成hash值
2、将hash值转为key
hashValue = hash_string(name, len);
index = hash_to_index(hashValue);
// Pick hashing algorithm
unsigned int StringTable::hash_string(const jchar* s, int len) {
return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) :
java_lang_String::hash_code(s, len);
}
// Bucket handling
int hash_to_index(unsigned int full_hash) {
int h = full_hash % _table_size;
assert(h >= 0 && h < _table_size, "Illegal hash value");
return h;
}
Value的生成方式
将Java的String类的实例instanceOopDesc封装成HashtableEntry
HashtableEntry<oop, mtSymbol>* entry = new_entry(hashValue, string());
add_entry(index, entry);
template <class T, MEMFLAGS F> HashtableEntry<T, F>* Hashtable<T, F>::new_entry(unsigned int hashValue, T obj) {
HashtableEntry<T, F>* entry;
entry = (HashtableEntry<T, F>*)BasicHashtable<F>::new_entry(hashValue);
entry->set_literal(obj);
return entry;
}
String.hashcode()
String类重写了hashcode方法
public int hashCode() {
int h = this.hash;
if (h == 0 && this.value.length > 0) {
char[] val = this.value;
for(int i = 0; i < this.value.length; ++i) {
h = 31 * h + val[i];
}
this.hash = h;
}
return h;
}
可以看出String的hashcode与String的内容是有关系的,因此下面的代码的hashcode是相等的
public class TestHashcode {
public static void main(String[] args) {
String s1 = "11";
String s2 = new String("11");
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
}
不同方式创建字符串在JVM中的存在形式
双引号
new String
两个双引号
两个new String
拼接字符串底层是如何实现的
双引号 + 双引号
public class TestString_5 {
public static void main(String[] args) {
}
public static void test2() {
String s1 = "1";
String s2 = "1";
String s = s1 + s2;
}
}
0 ldc #2 <1>
2 astore_0
3 ldc #2 <1>
5 astore_1
6 new #3 <java/lang/StringBuilder>
9 dup
10 invokespecial #4 <java/lang/StringBuilder.<init>>
13 aload_0
14 invokevirtual #5 <java/lang/StringBuilder.append>
17 aload_1
18 invokevirtual #5 <java/lang/StringBuilder.append>
21 invokevirtual #6 <java/lang/StringBuilder.toString>
24 astore_2
25 return
双引号 + new String
public class TestString_6 {
public static void main(String[] args) {
}
public static void test2() {
String s1 = "1";
String s2 = new String("1");
String s = s1 + s2;
}
}
0 ldc #2 <1>
2 astore_0
3 new #3 <java/lang/String>
6 dup
7 ldc #2 <1>
9 invokespecial #4 <java/lang/String.<init>>
12 astore_1
13 new #5 <java/lang/StringBuilder>
16 dup
17 invokespecial #6 <java/lang/StringBuilder.<init>>
20 aload_0
21 invokevirtual #7 <java/lang/StringBuilder.append>
24 aload_1
25 invokevirtual #7 <java/lang/StringBuilder.append>
28 invokevirtual #8 <java/lang/StringBuilder.toString>
31 astore_2
32 return
intern做了什么
常量池中有就直接返回
常量池中没有就创建一个,然后返回
练习
1、这句代码创建了几个对象?为什么?
String s1 = new String("子牙真帅");
2、这句代码创建了几个对象?为什么?
String s2 = "子牙" + "子牙";
3、这句代码创建了几个对象?为什么?
String s2 = "子牙" + new String("真帅");
4、将实例的intern代码的四个内存图画出来