ArrayList的remove、序列化(二)

对象的序列化作为一种存储对象为字节序列的方式,可以将对象保存到本地文件或者通过网络进行传输,是RMI对象或参数传递的基础。

对象的序列化会在输出流中保留一个序列化编号,当再次通过该对象输出流对同一个对象进行序列化时,只会存储一个编号,而不会存储整个对象。这种方式虽然可以保证在执行反序列化时,得到的仍然是同一个对象,但是同样使得第一次序列化后,对对象执行的修改在后续序列化中得不到保存,当然前提是使用同一个对象输出流,如果新建了输出流,则理所应当存储对象。

示例:

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的序列化和反序列化,依次保证只对数组有效元素部分进行序列化。






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值