ArrayList的remove、序列化(二)
2016-07-11 15:40
399 查看
对象的序列化作为一种存储对象为字节序列的方式,可以将对象保存到本地文件或者通过网络进行传输,是RMI对象或参数传递的基础。
对象的序列化会在输出流中保留一个序列化编号,当再次通过该对象输出流对同一个对象进行序列化时,只会存储一个编号,而不会存储整个对象。这种方式虽然可以保证在执行反序列化时,得到的仍然是同一个对象,但是同样使得第一次序列化后,对对象执行的修改在后续序列化中得不到保存,当然前提是使用同一个对象输出流,如果新建了输出流,则理所应当存储对象。
示例:
这里多说一句,待执行序列化的对象,其类必须实现了序列化接口,并且其内部属性,如果没有显式加transient修饰,则属性的类也必须实现序列化接口,该示例String,Number类都实现了序列化接口,否则会抛出NotSerializableException。
elementData是一个Object[]类型的数组,数组的容量大小是动态扩展的,最初为10,size反映的是有效表示的元素个数,从代码中可以看到,对于elementData数组的元素,进行序列化的只是有效的数据元素,而非elementData数组的全部容量。
示例:
ArrayList的elementData元素数组使用transient修饰,在ArrayList对象进行序列化时,将忽略该部分,由ArrayList对象控制对elementData的序列化和反序列化,依次保证只对数组有效元素部分进行序列化。
对象的序列化会在输出流中保留一个序列化编号,当再次通过该对象输出流对同一个对象进行序列化时,只会存储一个编号,而不会存储整个对象。这种方式虽然可以保证在执行反序列化时,得到的仍然是同一个对象,但是同样使得第一次序列化后,对对象执行的修改在后续序列化中得不到保存,当然前提是使用同一个对象输出流,如果新建了输出流,则理所应当存储对象。
示例:
class t2{ public static void main(String[] args){ Person p=new Person("xiaoming",18); ObjectOutputStream os=null; ObjectInputStream oi=null; try{ os=new ObjectOutputStream(new FileOutputStream("t1.txt")); os.writeObject(p);//第一次序列化 p.name="zhangsan";//方便起见,属性直接为public os.writeObject(p);//第二次序列化 oi=new ObjectInputStream(new FileInputStream("t1.txt")); Person p1=(Person)oi.readObject(); System.out.println("p1:"+p1); Person p2=(Person)oi.readObject(); System.out.println("p2:"+p2); System.out.println("p2==p1:"+(p2==p1)); }catch(Exception e){ e.printStackTrace(); }finally{ try{ if(os!=null){ os.close(); } }catch(IOException e){ e.printStackTrace(); } } } } class Person implements Serializable{ public String name; public int age; public Person(String name,int age){ this.name=name; this.age=age; } public String toString(){ return "name:"+name+",age:"+age; } } /* *输出结果为: *p1:name:xiaoming,age:18 *p2:name:xiaoming,age:18 *p2==p1:true */对象的修改没有得到保存。
这里多说一句,待执行序列化的对象,其类必须实现了序列化接口,并且其内部属性,如果没有显式加transient修饰,则属性的类也必须实现序列化接口,该示例String,Number类都实现了序列化接口,否则会抛出NotSerializableException。
关于ArrayList的序列化操作
ArrayList的属性表示为:private static final long serialVersionUID = 8683452581122892189L; private transient Object[] elementData; private int size;其中将elementData元素数组加以transient修饰,表示在ArrayList对象的序列化时,忽略数组的序列化。在ArrayList内部存在writeObject方法
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{ // Write out element count, and any hidden stuff int 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(); } }意思也就是在ArrayList对象序列化时,关于elementData元素数组部分的序列化的控制权,由ObjectOutputStream转移给ArrayList对象本身来控制。
elementData是一个Object[]类型的数组,数组的容量大小是动态扩展的,最初为10,size反映的是有效表示的元素个数,从代码中可以看到,对于elementData数组的元素,进行序列化的只是有效的数据元素,而非elementData数组的全部容量。
示例:
class t2{ public static void main(String[] args){ T_list<String> list=new T_list(10); list.add("first"); list.add("second"); ObjectOutputStream os=null; ObjectInputStream oi=null; try{ os=new ObjectOutputStream(new FileOutputStream("t1.txt")); os.writeObject(list); oi=new ObjectInputStream(new FileInputStream("t1.txt")); T_list<String> list1=(T_list<String>)oi.readObject(); }catch(Exception e){ e.printStackTrace(); }finally{ try{ if(os!=null){ os.close(); } }catch(IOException e){ e.printStackTrace(); } } } } class T_list<E> implements Serializable{ private transient Object[] elementData; private int size; public T_list(int capacity){ this.elementData=new Object[capacity]; size=0; } public void add(E e){ if(size==elementData.length){ throw new IndexOutOfBoundsException(); } elementData[size++]=e; } public int getElementsLength(){ return elementData.length; } private void writeObject(java.io.ObjectOutputStream s) throws Exception{ // Write out element count, and any hidden stuff 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]); } } private void readObject(java.io.ObjectInputStream s) throws Exception{ // Read in size, and any hidden stuff s.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(); } } }
总结:
对象的序列化会在输出流中保存一个对象的序列化编号,防止重复对一个对象进行多次保存,例如多个对象包含对同一个对象的引用,在序列化时只保存一次该引用对象。也避免了反序列化时,对同一个引用生成多个不同的对象。但是造成了在一次序列化之后,对象上的修改不能在再次序列化时保存。ArrayList的elementData元素数组使用transient修饰,在ArrayList对象进行序列化时,将忽略该部分,由ArrayList对象控制对elementData的序列化和反序列化,依次保证只对数组有效元素部分进行序列化。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序