为什么 'java.util.HashMap' 中的成员字段 'table' 是临时的?
Why member field 'table' in 'java.util.HashMap' is transient?
我了解到,transient
关键字可防止在序列化对象时保留使用 transient
关键字声明的实例字段的 值 。
下面是来自java.util.HashMap
的代码:
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
....
static class Node<K,V> implements Map.Entry<K,V> {...}
transient Node<K,V>[] table;
}
为什么实例字段 table
的值不是序列化的一部分?因为从实现的角度来看,table
字段的值是 class HashMap
实例的实际内容。
注意:here 是一个使用 transient 关键字的练习。
一个HashMap的实例有两个影响其性能的参数:初始容量和加载因子。容量是哈希 table 中的桶数,初始容量只是创建哈希 [=18=] 时的容量。
由于在您提到的示例中 'table' 是使用其他 2 个参数构建的,并由该数据结构用于表示,因此无需担心其序列化。
例如你可以在下面看到它:
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// Find a power of 2 >= initialCapacity
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
table = new Entry[capacity];
init();
}
How does one decide to not serialize a member by giving transient
modifier?
- 当字段引用的资源没有序列化意义时。例如,OutputStream 或 Window 句柄。
- 当字段可以从序列化的其他信息中重建时。这有助于减少需要写入的数据量。
For example, why member field table is not part of serialization?
因为(2)。看看 HashMap
class 中的 readObject
方法。 table
字段是使用 class.
中的其他信息重建的
因为Node<K, V>[] table
是稀疏的,把这个数组全部序列化很浪费时间。相反,我们只需要序列化数组中的非空元素就足以在以后重建table。
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
Node<K,V>[] tab;
if (size > 0 && (tab = table) != null) {
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next) {
s.writeObject(e.key);
s.writeObject(e.value);
}
}
}
}
我了解到,transient
关键字可防止在序列化对象时保留使用 transient
关键字声明的实例字段的 值 。
下面是来自java.util.HashMap
的代码:
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
....
static class Node<K,V> implements Map.Entry<K,V> {...}
transient Node<K,V>[] table;
}
为什么实例字段 table
的值不是序列化的一部分?因为从实现的角度来看,table
字段的值是 class HashMap
实例的实际内容。
注意:here 是一个使用 transient 关键字的练习。
一个HashMap的实例有两个影响其性能的参数:初始容量和加载因子。容量是哈希 table 中的桶数,初始容量只是创建哈希 [=18=] 时的容量。
由于在您提到的示例中 'table' 是使用其他 2 个参数构建的,并由该数据结构用于表示,因此无需担心其序列化。
例如你可以在下面看到它:
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// Find a power of 2 >= initialCapacity
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
table = new Entry[capacity];
init();
}
How does one decide to not serialize a member by giving transient modifier?
- 当字段引用的资源没有序列化意义时。例如,OutputStream 或 Window 句柄。
- 当字段可以从序列化的其他信息中重建时。这有助于减少需要写入的数据量。
For example, why member field table is not part of serialization?
因为(2)。看看 HashMap
class 中的 readObject
方法。 table
字段是使用 class.
因为Node<K, V>[] table
是稀疏的,把这个数组全部序列化很浪费时间。相反,我们只需要序列化数组中的非空元素就足以在以后重建table。
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
Node<K,V>[] tab;
if (size > 0 && (tab = table) != null) {
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next) {
s.writeObject(e.key);
s.writeObject(e.value);
}
}
}
}