引用就是堆空间的内存首地址。==的作用就是比较首地址。String中的数组是final所以是不可分割的。
1.java7使用intern方法时,如果常量池中不存在该字符串,那么字符串常量池里面保存的是堆中对象;当常量池存在的时候,那么intern返回的就是常量池中保存的引用,如何实现字符串常量池的不可重复性?
答:
(1)两种情况StringTable保存的都是String的引用,对象仍然创建在堆空间中,只不过在java7之后 不会重复生成对象了。
(2)StringTable中的key就是不重复的,所以石祥路字符串常量的不可重复。
2.为什么要使用intern方法?intern方法结果是什么?intern方法如何实现的?
答:
(1)利用intern方法使运行中的进程可以将字符串添加到字符串常量池(因为一个进程的堆中30%空间存储的都是String对象,同时14.5%的String对象还是重复的,这个时候使用intern就可减少内存资源浪费)
(2)intern就是将字符串的引用放到字符串常量池中
(3)通过StringTable中的WeakReference实现的
3.StringTable如何实现的?Map<String,WeakReference>为什么使用Reference找到已经存在key值?可以不使用Reference找到key值?
答:(1)如果不使用Reference那么就需要遍历集合,时间复杂度很高。
4.“1”是在什么时候加载到堆中的。
答:(1)在加载有“1”的class文件的时候就会加载。
关键提示:首先要明白HashTable添加元素比较的是hashcode()和equals()返回的值,这个和内存首地址概念是不同的。
通过下列代码感受一下Pool的作用:就是为了第二次寻找相同的字符串的时候返回第一次已经存在的字符串的内存地址。
public class TestPool {
final static Map<String,String> pool = new HashMap<>(1024);
public static void main(String[] args) {
// 不使用reference查找已经存在的字符串
String first00 = new String("0") + new String("0");
String second00 = "00";
// 发现first00 和 second00的内存首地址是不一致的所有返回false
System.out.println(first00 == second00);
// 如何根据second00的内存首地址找到first00的内存首地址,这里的方法就是没有使用reference。
String first = myintern(first00);
String second = myintern(second00);
System.out.println(first == second);
// 使用StringTable中的reference实现了唯一性。
String table1 = StringTable.intern(first00);
String table2 = StringTable.intern(second00);
System.out.println(table1==table2);
}
// 没有使用value值,仅仅根据key的遍历找到了最开始的String值,时间复杂度高。
public static String myintern(String str){
Set<String> arr = pool.keySet();
for(String s : arr){
if(s.equals(str)){
return s;
}
}
pool.put(str,null);
return str;
}
}
public class StringTable {
private static final Map<String, WeakReference<String>> pool = new HashMap<>(1009);
public static String intern(String str){
WeakReference<String> weakReference = pool.get(str);
if(weakReference!=null){
String res = weakReference.get();
if(res != null){
return res;
}
}
pool.put(str,new WeakReference<String>(str));
return str;
}
}