ArrayList源码分析——如何实现Serializable
???? 首先,序列化的实现方式:实现Serializable;如果提供了writeObject方法,就会在序列化的时候执行这个方法。看看ArrayList有是如何实现这个方法的。从如下源码中,很容易看到的一点是循环时i<size而不是i<elementData.length,看出端倪了吧,原来,序列化时,我们完全没有必要序列化elementData的所有值。
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{// Write out element count, and any hidden stuffint expectedModCount = modCount;s.defaultWriteObject(); // Write out array length s.writeInt(elementData.length);// Write out all elements in the proper order.for (int i=0; i<size; i++) s.writeObject(elementData[i]);if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } }????看这段源码又引出另外一个问题既然该方法是private的,那到底序列化的时候会不会派上用场呢?解决疑问的最好方式是实践,debug。如下是测试源码:
?
List<String> a = new ArrayList<String>(); a.add("hello"); a.add("world"); try { ByteArrayOutputStream st = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(st); out.writeObject(a); byte[] alBytes = st.toByteArray(); ArrayList<String> all = null;try {all = (ArrayList<String>) new ObjectInputStream( new ByteArrayInputStream(alBytes)).readObject();} catch (ClassNotFoundException e) {e.printStackTrace();} for(String s : all) { System.out.println(s); } } catch(IOException e) { } ??? 接下来,我们再看看ObjectOutputStream的writeObject又做了哪些事情。它会根据传进来的ArrayList对象得到Class,然后再包装成ObjectStreamClass,在writeSerialData方法里,会调用ObjectStreamClass的invokeWriteObject方法,最重要的代码如下:
writeObjectMethod.invoke(obj, new Object[]{ out });??? 实例变量writeObjectMethod的赋值方式如下:
?
writeObjectMethod = getPrivateMethod(cl, "writeObject", new Class[] { ObjectOutputStream.class }, Void.TYPE); private static Method getPrivateMethod(Class cl, String name, Class[] argTypes, Class returnType) {try { Method meth = cl.getDeclaredMethod(name, argTypes); //*****通过反射访问对象的private方法 ?meth.setAccessible(true); int mods = meth.getModifiers(); return ((meth.getReturnType() == returnType) && ((mods & Modifier.STATIC) == 0) && ((mods & Modifier.PRIVATE) != 0)) ? meth : null;} catch (NoSuchMethodException ex) { return null;} }??? 到此为止,我们已经很清楚的掌握ArrayList的序列化过程。再看看HashMap等其他容器类,序列化的实现都如出一辙。
?? 反序列化的过程是调用readObject方法,有了writeObject介绍,这个方法就不用介绍了吧,你懂的!
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {// Read in size, and any hidden stuffs.defaultReadObject(); // Read in array length and allocate array int arrayLength = s.readInt(); Object[] a = elementData = new Object[arrayLength];// Read in all elements in the proper order.for (int i=0; i<size; i++) a[i] = s.readObject(); }