7.Serializable和Parcelable

来源:互联网 发布:java ping 域名是否通 编辑:程序博客网 时间:2024/05/16 02:16
Serializable和Parcelable接口可以完成对象的序列化过程,当我们需用使用Intent 和Binder 传输数据的时候,就需要使用到Parcel和Serializable.而有时候,我们需要持久化数据、或者是传输数据到网络上,我们也要使用Serializable来完成对象的序列化。
    
    7.1Serializable接口
    实现序列化接口,很简单,只需要实现它,就好,当然,最好是赋予它一个serialVersionUId (序列化ID)。不声明序列化ID,其实也可以序列化,但是,可能会对反序列化有影响。下面我们就简单介绍序列化和反序列化的过程:
        假设我们有一个User类如下:
        
public class User impelements Serializable{                    private static final long serialVersionUID = 519606712346586214L;            public int userId;            public String userName;                    }


        序列化过程需要用到ObjectOutputStream下面是序列化的过程:
        
        
User user = new User();        user.userId= 12;        user.userName = "张三";        ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream( "cache.txt") );        out.writeObject( user );        out.close();


        通过上面的代码,对象就序列化到了cache.txt文件上了。
        而这时候,我们希望能够把文件在变成对象,该怎么做呢?
        就要进行反序列化过程,序列化的过程我们是使用ObjectOutputStream 那么反序列化当然是用ObjectInputStream
        
 ObjectInputStream in = new ObjectOutputStream( new FileInputStream( "cache.txt"));         in.readObject();         in.close();

         通过上面的代码,我们就能把对象从文件当中恢复,恢复出来的内容是完全一样的,但是他们不是同一个对象。
         现在,我们在这边来讨论下serialVersionUID的作用吧,首先,就要从反序列化过程入手:
         反序列化的时候,系统会查看文件的序列化ID,如果序列化ID一致,那么就会进行序列化,因为这代表对象是一样的,反之,则不会,因为序列化ID不一样说明了这个类已经被改变了,比如成员数量变化、类型变化,这时候就会反序列化失败。一般来说,我们要手动指定UID值,或者是用Eclipse等工具在创建的时候自动生成一个hash值,如果我们不指定会怎么样?不指定的话,系统序列化的时候,会把当前类的hash值作为序列化ID,那么当我们反序列化的时候,如果这个类改变了,那么hash值就会改变,那么就会造成序列化ID不一样,那么就导致了反序列化失败。
        简单地说,不指定ID的话,我们存储User 时候有2个变量,而我们想获取原来User的数据的时候,我们改变了User类,改成了3个变量.增加了学号:number
这时候,从cache.txt想反序列化是不行的,因为cache的那个User是2个变量的User ,2个变量的User和3个变量的User的hash值改变了,所以系统认为两个不是一个版本的类,所以反序列化失败。
    值得一提的是,序列化ID一样,并不一定会保证反序列化成功,比如我把userName从String改成了int,这样就会破坏了类的结构,或者是我改了类名也会造成这种情况。

    7.2Parcelable接口
        Parcelable也是一个接口,只要实现这个接口,这个类的对象就可以实现序列化,并且可以通过Intent和Biner进行传递。
        下面是实现了Parcelable的例子:
public class User implements Parcelable {    public int userId;    public String userName;    public boolean isMale;    public Book book;    public User( int userId, String userName , boolean isMale )    {        this.userId = userId;        this.userName = userName;        this.isMale = isMale;    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel out, int arg1) {        out.writeInt( userId );        out.writeString(userName);        out.writeInt( isMale ? 1:0 );        out.writeParcelable(book, 0);    }    public Parcelable.Creator< User> CREATOR = new Parcelable.Creator<User>() {        @Override        public User createFromParcel(Parcel arg0) {             return new User(arg0) ;        }        @Override        public User[] newArray(int arg0) {            // TODO Auto-generated method stub            return new User[arg0];        }    };    private User( Parcel in )    {        userId = in.readInt();        userName = in.readString();        isMale = in.readInt() == 1 ? true : false;        book = in.readParcelable( Thread.currentThread().getContextClassLoader());    }}


可以看到,反序列化的过程是由CREATOR来实现的。
        系统已经为我们提供了很多实现了Parcelable的类,它们都是可以直接序列化的,比如Intent、Bundle、Bitmap等,
 同时List和Map也可以序列化,前提是它们里面的每个元素都是可以序列化的。
        Serializable是Java的接口,它使用起来比较简单,但是开销大,因为需要大量的I/O操作。而Parcel是Anroid多肚饿,他的效率比较高,适合用在内存交换当中,而如果是持久化数据或者是网路传输,采用Serializble比较好,因为Parcel实现比较复杂(也是可以持久化和传输)。
   

    
    
    
0 0