???????????
????Android????LRUCache????????????????????LRU??????檔Java????LinkedHashMap???????????????????LRU????Java??LRULinkedHashMap?????????LinkedHashMap??????????????????????LRU????
????????Java??LRU??
????Java??LRU?????????LinkedHashMap??LinkedHashMap?????HashMap????????HashMap??????????????????????????LRU????
????1??HashMap
???????????????????HashMap?????????????洢??Entry<K??V>???С?Entry<K??V>?д洢????????key??value??hash????????洢????????????????????á????Entry<K??V>??????????????HashMap??洢?????????????????????????????key?????hashCode????HashMap???????ж???????????λ???????????key??????????hashCode????????????????ж?????????λ??????????HashMap??????????????Entry<K??V>?У????????????????ЩEntry<K??V>??
static class Entry<K??V> implements Map.Entry<K??V> {
final K key;
V value;
Entry<K??V> next;
int hash;
/**
* Creates new entry.
*/
Entry(int h?? K k?? V v?? Entry<K??V> n) {
value = v;
next = n;
key = k;
hash = h;
}
public final K getKey() {
return key;
}
public final V getValue() {
return value;
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public final int hashCode() {
return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
}
public final String toString() {
return getKey() + "=" + getValue();
}
/**
* This method is invoked whenever the value in an entry is
* overwritten by an invocation of put(k??v) for a key k that's already
* in the HashMap.
*/
void recordAccess(HashMap<K??V> m) {
}
/**
* This method is invoked whenever the entry is
* removed from the table.
*/
void recordRemoval(HashMap<K??V> m) {
}
}
?????????????HashMap??put??????????????з???
public V put(K key?? V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
//??????????????????????????????????
//???????hashCode
int hash = hash(key);
//???????????hashCode???????hashCode???????е?λ??
int i = indexFor(hash?? table.length);
//for??????????HashMap???????????????????key?????key?????????????????????????滻??key?????value??????????滻value????????
for (Entry<K??V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//?????е?????????HashMap?в??????????μ?kye.????addEntry?????????????key??value????????????HashMap??
modCount++;
addEntry(hash?? key?? value?? i);
return null;
}
???????????????????????Щ??????????????????????????????Щ??÷??????????????
????<1> int i = indexFor(hash?? table.length);
???????????????
????static int indexFor(int h?? int length) {
????// assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
????return h & (length-1);
????}
???????????hashCode(h)???(length-1)???а?λ????????????????????h???λ?????????????С?8??1000?????????????h????10??1010?????????????????index?10??????????????????鳬????????????????e?λ??0111&1010?????????????λ????????2??0010????????????????index?2???????Ч????????????????λ?????Ч??????????
????????????????????????length?9???????length-1????8??1000????????????λ?????????????????λ??????????????????????????????С???????????????????????????????HashMap????????????????????????2??n?η???
??????????put?????????inflateTable?????????????roundUpToPowerOf2??????????????????????????λ???????????????п?????????????????????????????????????2??n?η???
????private void inflateTable(int toSize) {
????// Find a power of 2 >= toSize
????int capacity = roundUpToPowerOf2(toSize);
????threshold = (int) Math.min(capacity * loadFactor?? MAXIMUM_CAPACITY + 1);
????table = new Entry[capacity];
????initHashSeedAsNeeded(capacity);
????}
??????Σ???addEntry??????λ??????????2 * table.length????table.length << 1??????????????????2??n?η???
????<2> for (Entry<K??V> e = table[i]; e != null; e = e.next)
???????HashMap????????????????????????????hashCode????????????е?λ?ú????????????Entry<K??V>?????????Entry<K??V>??????????????????????key?????value??
????<3> addEntry(hash?? key?? value?? i);
???????ж?????????????????????????????????????????????????????Entry????????????С?
/**
* Adds a new entry with the specified key?? value and hash code to
* the specified bucket.  It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash?? K key?? V value?? int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash?? table.length);
}
createEntry(hash?? key?? value?? bucketIndex);
}
/**
* Like addEntry except that this version is used when creating entries
* as part of Map construction or "pseudo-construction" (cloning??
* deserialization).  This version needn't worry about resizing the table.
*
* Subclass overrides this to alter the behavior of HashMap(Map)??
* clone?? and readObject.
*/
void createEntry(int hash?? K key?? V value?? int bucketIndex) {
Entry<K??V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash?? key?? value?? e);
size++;
}
????2??LinkedHashMap
????LinkedHashMap??HashMap???????????????????????Entry?????????????????????????before??after??????Entry?????á?
private static class Entry<K??V> extends HashMap.Entry<K??V> {
// These fields comprise the doubly linked list used for iteration.
Entry<K??V> before?? after;
Entry(int hash?? K key?? V value?? HashMap.Entry<K??V> next) {
super(hash?? key?? value?? next);
}
/**
* Removes this entry from the linked list.
*/
private void remove() {
before.after = after;
after.before = before;
}
/**
* Inserts this entry before the specified existing entry in the list.
*/
private void addBefore(Entry<K??V> existingEntry) {
after  = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
/**
* This method is invoked by the superclass whenever the value
* of a pre-existing entry is read by Map.get or modified by Map.set.
* If the enclosing Map is access-ordered?? it moves the entry
* to the end of the list; otherwise?? it does nothing.
*/
void recordAccess(HashMap<K??V> m) {
LinkedHashMap<K??V> lm = (LinkedHashMap<K??V>)m;
if (lm.accessOrder) {
lm.modCount++;
remove();
addBefore(lm.header);
}
}
void recordRemoval(HashMap<K??V> m) {
remove();
}
}
????????LinkedHashMap?????????Entry??????header??private transient Entry<K??V> header????header??????????????HashMap?????г???????header.after????β(header.before)????????HashMap?????????????????????????????LinkedHashMap?У?????????HashMap??????????????????????????????????header?????????????????????????????header????????????LinkedHashMap?????header??????????????LRU?????header.after?????????????????????????????????????header.after????????????header.before??????????ù?????????
????LinkedHashMap???????put??????????LinkedHashMap??д??addEntry??createEntry?????????£?
/**
* This override alters behavior of superclass put method. It causes newly
* allocated entry to get inserted at the end of the linked list and
* removes the eldest entry if appropriate.
*/
void addEntry(int hash?? K key?? V value?? int bucketIndex) {
super.addEntry(hash?? key?? value?? bucketIndex);
// Remove eldest entry if instructed
Entry<K??V> eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
}
}
/**
* This override differs from addEntry in that it doesn't resize the
* table or remove the eldest entry.
*/
void createEntry(int hash?? K key?? V value?? int bucketIndex) {
HashMap.Entry<K??V> old = table[bucketIndex];
Entry<K??V> e = new Entry<>(hash?? key?? value?? old);
table[bucketIndex] = e;
e.addBefore(header);
size++;
}
????HashMap??put????????????addEntry??????HashMap??addEntry???????????createEntry????????????????????????????HashMap?е????????????????????γ????·?????
void addEntry(int hash?? K key?? V value?? int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash?? table.length);
}
HashMap.Entry<K??V> old = table[bucketIndex];
Entry<K??V> e = new Entry<>(hash?? key?? value?? old);
table[bucketIndex] = e;
e.addBefore(header);
size++;
// Remove eldest entry if instructed
Entry<K??V> eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
}
}
????????????ж????????????????????????????????????Entry??????????HashMap???????????????С???HashMap???????LinkedHashMap??????e.addBefore(header);??removeEntryForKey(eldest.key);??????????????
??????????????e.addBefore(header)??????e??LinkedHashMap.Entry????addBefore???????£????????header???????????????????????????header??????????β????header.before????
????private void addBefore(Entry<K??V> existingEntry) {
????after  = existingEntry;
????before = existingEntry.before;
????before.after = this;
????after.before = this;
????}
????????????????????????£?
????// Remove eldest entry if instructed
????Entry<K??V> eldest = header.after;
????if (removeEldestEntry(eldest)) {
????removeEntryForKey(eldest.key);
????}