這本篇博客里面我想重點來分析一下ContentValues的源碼以及它里面涉及到的繼承接口Parcelabel,還有HashMap的源碼。
相信使用過android里面數據庫操作的朋友對於ContentValues一定不會感到陌生吧,它其實很像一個字典對象,可以用來存儲鍵值對。比如代碼如下:
ContentValues contentValues=new ContentValues();
contentValues.put("name","xiao");
contentValues.put("age",20);
contentValues.put("isStudent",true);
你會發現ContentValues里面可以用來put各種類型的數據,它是怎樣擁有這種神奇的功能的呢?下面讓我們來看看它的源碼。首先,是ContentValues類的定義:
public final class ContentValues implements Parcelable {
}
我們可以看到它實現了Parcelabel接口,這個接口主要是用來實現數據安裝、傳輸相關操作的。說到這里,讓我們也來看看Parcelabel接口里面到底定義了哪些方法,源碼如下:
public interface Parcelable {
public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;
public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;
public int describeContents();
public void writeToParcel(Parcel dest, int flags);
public interface Creator<T> {
public T createFromParcel(Parcel source);
public T[] newArray(int size);
}
public interface ClassLoaderCreator<T> extends Creator<T> {
public T createFromParcel(Parcel source, ClassLoader loader);
}
}
我們可以看到里面有個writeToParcel方法是用來傳輸數據的,至於它是怎么用來包裝數據的,就要看看具體實現Parcelabel接口類的實現了。
好了說回我們所要討論的重點對象ContentValues,首先來看看ContentValues里面包括的構造函數,源碼如下所示:
private HashMap<String, Object> mValues;
public ContentValues() {
// Choosing a default size of 8 based on analysis of typical
// consumption by applications.
mValues = new HashMap<String, Object>(8);
}
/**
* Creates an empty set of values using the given initial size
*
* @param size the initial size of the set of values
*/
public ContentValues(int size) {
mValues = new HashMap<String, Object>(size, 1.0f);
}
/**
* Creates a set of values copied from the given set
*
* @param from the values to copy
*/
public ContentValues(ContentValues from) {
mValues = new HashMap<String, Object>(from.mValues);
}
/**
* Creates a set of values copied from the given HashMap. This is used
* by the Parcel unmarshalling code.
*
* @param values the values to start with
* {@hide}
*/
private ContentValues(HashMap<String, Object> values) {
mValues = values;
}
相信大家從注釋里面就能夠看看,ContentValues的構造主要是根據代碼里面傳入的具體參數來構造對應的HashMap對象,然后里面的各種put操作、get操作、remove操作都是針對HashMap進行的,其中put類型的方法源碼如下:
public void put(String key, String value) {
mValues.put(key, value);
}
public void putAll(ContentValues other) {
mValues.putAll(other.mValues);
}
public void put(String key, Byte value) {
mValues.put(key, value);
}
public void put(String key, Short value) {
mValues.put(key, value);
}
public void put(String key, Integer value) {
mValues.put(key, value);
}
public void put(String key, Long value) {
mValues.put(key, value);
}
public void put(String key, Float value) {
mValues.put(key, value);
}
public void put(String key, Double value) {
mValues.put(key, value);
}
public void put(String key, Boolean value) {
mValues.put(key, value);
}
public void put(String key, byte[] value) {
mValues.put(key, value);
}
public void putNull(String key) {
mValues.put(key, null);
}
通過上面的方法,我們就能夠明白為什么ContentValues能夠put各種類型的數值了吧,接下來讓我們來看看get方法,源碼如下:
public Object get(String key) {
return mValues.get(key);
}
public String getAsString(String key) {
Object value = mValues.get(key);
return value != null ? value.toString() : null;
}
public Long getAsLong(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).longValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Long.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Long value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Long: " + value, e);
return null;
}
}
}
public Integer getAsInteger(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).intValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Integer.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Integer value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Integer: " + value, e);
return null;
}
}
}
public Short getAsShort(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).shortValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Short.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Short value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Short: " + value, e);
return null;
}
}
}
public Byte getAsByte(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).byteValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Byte.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Byte value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Byte: " + value, e);
return null;
}
}
}
public Double getAsDouble(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).doubleValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Double.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Double value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Double: " + value, e);
return null;
}
}
}
public Float getAsFloat(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).floatValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Float.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Float value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Float: " + value, e);
return null;
}
}
}
public Boolean getAsBoolean(String key) {
Object value = mValues.get(key);
try {
return (Boolean) value;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
return Boolean.valueOf(value.toString());
} else if (value instanceof Number) {
return ((Number) value).intValue() != 0;
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Boolean: " + value, e);
return null;
}
}
}
public byte[] getAsByteArray(String key) {
Object value = mValues.get(key);
if (value instanceof byte[]) {
return (byte[]) value;
} else {
return null;
}
}
通過上面的代碼我們也能很直觀的看到,不同的get方法通過調用不同類型的((Number)value).intValue方法強轉一次獲取,如果拿不到的話就返回null。
既然ContentValues是基於HashMap去實現操作的,那么我們有必要來看看HashMap到底是怎么回事?首先是HashMap類定義,源碼如下所示:
public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable{
}
通過上面的代碼,我們可以看到HashMap是基於泛型去構建的,同時實現了克隆和序列化接口。這就意味着在一定程度上面,我們可以實例化任何類型的HashMap,並且使它具有克隆、序列化的功能,請看如下代碼:
HashMap<Integer,Object> hashOne=new HashMap<>(); HashMap<String,Object> hashTwo=new HashMap<>(); HashMap<Boolean,Object> hashThree=new HashMap<>(); HashMap<Float,Object> hashFour=new HashMap<>();
只不過我們通常在項目里面一般都習慣使用String類型的key。好了,讓我們繼續往下看,首先最應該說的就是HashMapEntry內部靜態類了,源碼如下:
static class HashMapEntry<K, V> implements Entry<K, V> {
final K key;
V value;
final int hash;
HashMapEntry<K, V> next;
HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) {
this.key = key;
this.value = value;
this.hash = hash;
this.next = next;
}
public final K getKey() {
return key;
}
public final V getValue() {
return value;
}
public final V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
@Override public final boolean equals(Object o) {
if (!(o instanceof Entry)) {
return false;
}
Entry<?, ?> e = (Entry<?, ?>) o;
return Objects.equal(e.getKey(), key)
&& Objects.equal(e.getValue(), value);
}
@Override public final int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}
@Override public final String toString() {
return key + "=" + value;
}
}
HashMapEntry類實現了Entry接口,而Entry接口又是Map接口里面的一個內部接口。通過實現Entry接口,從而使HashMap具有了getKey/getValue/setValue等相關功能。同時我們可以看到HashMap里面好多功能的實現都是針對HashMapEntry展開的。另外HashMap還有個比較重要的概念就是Set接口,讓我們來看看里面final類型的私有內部類EntrySet,源碼如下:
private final class EntrySet extends AbstractSet<Entry<K, V>> {
public Iterator<Entry<K, V>> iterator() {
return newEntryIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Entry))
return false;
Entry<?, ?> e = (Entry<?, ?>) o;
return containsMapping(e.getKey(), e.getValue());
}
public boolean remove(Object o) {
if (!(o instanceof Entry))
return false;
Entry<?, ?> e = (Entry<?, ?>)o;
return removeMapping(e.getKey(), e.getValue());
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void clear() {
HashMap.this.clear();
}
}
正如其名一樣,Set接口里面主要是提供HashMap的設置相關操作。讓我們來看看Set接口里面的源碼,如下:
public boolean add(E object);
public boolean addAll(Collection<? extends E> collection);
public void clear();
public boolean contains(Object object);
public boolean containsAll(Collection<?> collection);
public boolean equals(Object object);
public int hashCode();
public boolean isEmpty();
public Iterator<E> iterator();
public boolean remove(Object object);
public boolean removeAll(Collection<?> collection);
public boolean retainAll(Collection<?> collection);
public int size();
public Object[] toArray();
public <T> T[] toArray(T[] array);
好了,今天博客就到這里。技術有限,如有不對歡迎拍磚!
