序列化
首先我们大家都知道,我们的Java程序它是一直在内存中跑的,然后如果我们需要将一个对象持久化或者在网络中传输的话,那么我们就需要进行序列化,将其转化为二进制;
然后在阅读源码的时候,我们都知道所有容器的底层都会有个存储变量,可能为数组或者其他数据结构,但是我发现基本上所有的容器它底层存储变量都添加了transient修饰符,该修饰符便代表着它并不能进行序列化操作,序列化操作的时候会忽略它;
那么感觉与我们所了解的不符合,那么我们就会非常奇怪,接下来用简短的一篇文章来介绍一下具体细节;
序列化具体原理
在之前学习大数据的时候,书上说我们需要重写MapReduce中的对象的序列化方法writerObject与readObject,于是我去查阅HashMap的源码,发现确实有这两个方法:
private void writeObject(java.io.ObjectOutputStream s)
throws IOException {
int buckets = capacity();
s.defaultWriteObject();
s.writeInt(buckets);
s.writeInt(size);
internalWriteEntries(s);
}
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
reinitialize();
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new InvalidObjectException("Illegal load factor: " +
loadFactor);
s.readInt();
int mappings = s.readInt();
if (mappings < 0)
throw new InvalidObjectException("Illegal mappings count: " +
mappings);
else if (mappings > 0) {
float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
float fc = (float)mappings / lf + 1.0f;
int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
DEFAULT_INITIAL_CAPACITY :
(fc >= MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY :
tableSizeFor((int)fc));
float ft = (float)cap * lf;
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
table = tab;
for (int i = 0; i < mappings; i++) {
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false);
}
}
}
可以看到,他其实重写了这两个方法,然后将一些重要的信息写入二进制文件,其他不重要的就不管;
启示
Java容器的这个设计细节我们在写项目中也可以得到启示,我们有时候只需要关注重要的信息,一些不重要的信息可以进行删减;
|