Serializable接口描述

Serializable

package java.io;
public interface Serializable {
}

以上是它的源代码 什么都没有。

如果一个接口里面什么内容都没有,那么这个接口是一个标识接口。标识接口是没有任何方法和属性的接口。标识接口不对实现它的类有任何语义上的要求,它仅仅表明实现它的类属于一个特定的类型。

序列化定义

    对象的寿命通常随着生成该对象的程序的终止而终止,而有时候需要把在内存中的各种对象的状态(也就是实例变量,不是方法)保存下来,并且可以在需要时再将对象恢复。 Java提供了一种保存对象状态的机制,那就是序列化。说白了就是讲序列化标记的对象转换成字节序列。

什么时候需要序列化

对于javabean来说,对象的序列化是必须的,使用一个bean时,一般情况是在设计阶段对他的状态信息进行配置。这种配置信息必须要保存下来,并在程序启动的时候进行后期恢复。
想把对象通过网络进行传播的时候,例如RMI,他使存活于其他计算机上的对象使用起来就像是存活在本机上一样。

如何序列化

只要一个类实现Serializable接口,那么这个类就可以序列化了。

实例

class Person implements Serializable{
    private static final long serialVersionUID = 1L; 
    private String name;
    private int age;
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }   
    public String toString(){
        return "name:"+name+" age:"+age;
    }
}

调用 ObjectOutputStream 的writeObject()方法可以完成对象的序列化

通过 ObjectInputStream    的readObject()方法把这个对象读出来

Person person = new Person("刘京晖", 18); //定义一个对象

File file = new File("file"+File.separator+"out.txt");
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(file);
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(fos);
            oos.writeObject(person);            
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                oos.close();
            } catch (IOException e) {e.printStackTrace();}
        }
    } catch (Exception e) {e.printStackTrace();} 
      finally{
        try {
            fos.close();
        } catch (Exception e) {e.printStackTrace();}
    }

    FileInputStream fis = null;
    try {
        fis = new FileInputStream(file);
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(fis);
            try {
                Person person = (Person)ois.readObject();
            } catch (Exception e) {e.printStackTrace();} 
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                ois.close();
            } catch (Exception e) {e.printStackTrace();}
        }
    } catch (Exception e) {e.printStackTrace();} finally{
        try {
            fis.close();
        } catch (Exception e) {e.printStackTrace();}
    }


输出

name:刘京晖 age:18
name:刘京晖 age:18


serialVersionUID

注意到上面程序中有一个 serialVersionUID ,实现了Serializable接口之后,Eclipse就会提示你增加一个 serialVersionUID,虽然不加的话上述程序依然能够正常运行。

序列化 ID 在 Eclipse 下提供了两种生成策略

一个是固定的 1L 
一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具,根据类名、接口名、成员方法及属性等来生成) 
上面程序中,输出对象和读入对象使用的是同一个Person类。

如果是通过网络传输的话,如果Person类的serialVersionUID不一致,那么反序列化就不能正常进行。例如在客户端A中Person类的serialVersionUID=1L,而在客户端B中Person类的serialVersionUID=2L 那么就不能重构这个Person对象。

试图重构就会报java.io.InvalidClassException异常,因为这两个类的版本不一致,local class incompatible,重构就会出现错误。

默认的使用1L 就可以,这样可以确保代码一致时反序列化成功。

那么随机生成的序列化 ID 有什么作用呢,有些时候,通过改变序列化 ID 可以用来限制某些用户的使用。

序列化保存的是对象的状态,静态变量属于类的状态,不能保存任何的成员方法和静态的成员变量


transient(瞬时)关键字

说白了这个关键字的作用就是不保存一些敏感的信息到字节流中,例如一些Login对象,你可不能告诉别人密码用户名啊。

使用起来也很简单,只需在关键的成员变量,如密码等 需要加上transient关键字

例如用 transient关键字 修饰password变量

class Person implements Serializable{   
    private static final long serialVersionUID = 1L;
    String name;
    transient int password;

    public Person(String name,int password){
        this.name = name;
        this.password= password;
    }   
    public String toString(){
        return "name:"+name+" age:"+password;
    }
}

在反序列化视图重构对象的时候,作用与static变量一样: 输出结果为:

name:刘京晖 password:0

在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

注:对于某些类型的属性,其状态是瞬时的,这样的属性是无法保存其状态的。例如一个线程属性或需要访问IO、本地资源、网络资源等的属性,对于这些字段,我们必须用transient关键字标明,否则编译器将报措。

序列化中的继承问题

当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口; 
一个子类实现了 Serializable 接口,它的父类都没有实现 Serializable 接口,要想将父类对象也序列化,就需要让父类也实现Serializable 接口。 
第二种情况中:如果父类不实现 Serializable接口的话,就需要有默认的无参的构造函数。这是因为创建java 对象的时候需要先有父对象,才有子对象,反序列化也不例外。在反序列化时,为了构造父对象,只能调用父类的无参构造函数作为默认的父对象。因此当我们取父对象的变量值时,它的值是调用父类无参构造函数后的值。在这种情况下,在序列化时根据需要在父类无参构造函数中对变量进行初始化,否则的话,父类变量值都是默认声明的值,如 int 型的默认是 0,string 型的默认是 null。

猜你喜欢

转载自blog.csdn.net/qq_31615049/article/details/80250730