一、Java數據類型
數據類型就是對內存位置的抽象表達
(很多編程語言都依賴于特定的計算機類型和對數據類型屬性的具體編譯實現,比如word和integer數據類型的大小等;Java通過JVM保證數據所占存儲空間的大小不會隨硬件的改變發生變化)。
1. Primitive data type :A primitive type is predefined by
the language and is named by a reserved keyword. Primitive values do not share
state with other primitive values. The eight primitive data types supported by
the Java programming language。
原生類型是語言自身預先定義的,原生值不會與其他原生值共享狀態。有8中原生類型被Java語言支持,如下:
byte(8位)、short(16位)、int(32位)、long(64位)、float(浮點數,32位)、double(浮點數,64位)、boolean(1位,只有true或false可取)、char(16-bit Unicode character)
2.
復雜數據類型
運行期動態創建,一切皆為對象。
接口(定義行為)
類(String objects
are immutable, which means that once created, their values cannot be changed.)
數組
引用(軟、弱、虛引用)
二、Reference分類
1. strong Reference :正常情況下的引用都屬于strong引用,如:String str = new String();str是strong reference。其它引用必須是顯式的聲明,如:SoftReference
softRef = new SoftReferencne(str),softRef是弱引用。
2. SoftReference :軟引用。在內存溢出前,垃圾收集器將回收其引用的對象;
3. WeakReference :弱引用。任何垃圾回收,掃描到弱引用時,其引用的對象都會被回收。
4. PhantomReference :不理解。
補充:ReferenceQueue
Reference
queues, to which registered reference objects are appended by the garbage
collector after the appropriate reachability changes are detected.
當某個引用對象的可達性被垃圾搜集器改變或清除后,會被放入對應的 ReferenceQueue 中(如果注冊引用隊列)。
String str = new String("hello");
ReferenceQueue<String> refQuence = new
ReferenceQueue<String>();
Str = null;
SoftReference<String> softRef =
new
SoftReference<String>(str, refQuence);
如上例:當“hello”對象被收回后,則softRef會被加入到ReferenceQueue。
三、
WeakHashMap簡單分析
簡化WeakHashMap結構:
class WeakHashMap<K, V> {
private final ReferenceQueue<K> queue = new ReferenceQueue<K>();
private Entry[] table;
private static class Entry<K,V> extends WeakReference<K> implements
Map.Entry<K,V> {
}
}
分析:WeakHashMap的put方法(Map對數據的保存也是通過數組實現)
public V put(K
key, V value) {
K k = (K) maskNull(key);
int h = HashMap.hash(k.hashCode());
Entry[] tab = getTable(); //獲取table(關鍵:調用expungeStaleEntries方法,清洗table數組中,value所指的實際對象已被GC)
int i = indexFor(h, tab.length); //根據key.hash計算在數組的位置
//從此位置開始,遍歷單向鏈表,判斷此位置是否已經存在相同元素
//1.有。更新為value
//2.無,創建新的對象,置原頭部元素為自己的next,讓自身為單向鏈表頭部
for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
//如果hash相等,且equals相等
if (h == e.hash && eq(k, e.get())) {
V oldValue = e.value;
if (value != oldValue)
e.value = value;
return oldValue;
}
}
modCount++;
Entry<K,V> e =
tab[i];
//queue是ReferenceQueue,h自身key計算得到的hash值,e指向單鏈表下一個節點next
tab[i] = new Entry<K,V>(k, value, queue, h, e);
if (++size >= threshold) //判斷數組容量是否需要擴充,策略:2倍
resize(tab.length * 2);
return null;
}
/*
* 清洗已被gc對象的引用,釋放數組的容量
*/
private void expungeStaleEntries()
{
Entry<K,V> e;
while ( (e = (Entry<K,V>) queue.poll()) != null) { //從隊列獲取第一個加入ReferenceQueue的引用,循環
int h = e.hash;
int i = indexFor(h, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) { //檢查單鏈表的數據是否已陳舊,清洗
Entry<K,V> next = p.next;
if (p == e) { //若相等,說明引用的對象已被gc
if (prev == e)
table[i] = next;
else
prev.next = next;
//因為其引用對象被垃圾收集器改變可達性時,也會被放入queue,所以強制設置其next、value為null,幫助gc收集其引用對象(不這樣的理解正確不?請大家指點)
e.next = null; // Help GC
e.value = null; // "
"
size--;
break;
}
prev = p;
p = next;
}
}
}
四、
總結
引用也是屬于Java的比較特殊的數據類型,對于軟、弱引用的使用場景大多是“緩存”。