Java对象序列化


一、---概念---



Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些

对象生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在

将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。

如果某个类能够被序列化,其子类也可以被序列化。声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态, transient代表对象的临时数据。



二、---Serializable---



下面是一个默认序列化的例子,是通过文件流的方式来将对象进行序列化的。

默认的序列化机制,是对对象的所有成员变量(静态变量不会被序列化,因为它不属于某个对象,是所有对象共享的)进行序列化,而

且,假如,成员变量中有对象引用,也会对这个对象引用指向的对象实例进行序列化,如果这个对象实例也包含有其它对象引用,

也会把那些对象进行序列化,以此类推。因此,如果是一个比较复杂的对象实例,比如集合类对象,集合元素也是集合类对象,那

么其序列化过程会比较复杂,开销较大。


import java.io.Serializable;     
    
public class Student implements Serializable {     
    
    int id;// 学号     
    
    String name;// 姓名     
    
    int age;// 年龄     
    
    String password; // 密码     
    
    public Student(int id, String name, int age, String password) {     
    
        this.id = id;     
    
        this.name = name;     
    
        this.age = age;     
    
        this.password = password;     
    
    }     
    
}    
如下是对Student对象的序列化以及输出结果:

import java.io.FileInputStream;     
import java.io.FileOutputStream;     
import java.io.IOException;     
import java.io.ObjectInputStream;     
import java.io.ObjectOutputStream;     
    
public class ObjectSer {     
    
    public static void main(String args[]) throws IOException,     
            ClassNotFoundException {     
    
        Student stu = new Student(981036, "LiuMing", 18, "123456");     
    
        FileOutputStream fo = new FileOutputStream("data.ser");     
    
        ObjectOutputStream so = new ObjectOutputStream(fo);     
    
        try {     
    
            so.writeObject(stu);     
    
            so.close();     
    
        } catch (IOException e) {     
            System.out.println(e);     
        }     
    
        stu = null;     
    
        FileInputStream fi = new FileInputStream("data.ser");     
    
        ObjectInputStream si = new ObjectInputStream(fi);     
    
        try {     
    
            stu = (Student) si.readObject();     
    
            si.close();     
    
        } catch (IOException e)     
    
        {     
            System.out.println(e);     
        }     
    
        System.out.println("Student Info:");     
    
        System.out.println("ID:" + stu.id);     
    
        System.out.println("Name:" + stu.name);     
    
        System.out.println("Age:" + stu.age);     
    
        System.out.println("Passw:" + stu.password);     
    
    }     
    
}    
运行结果如下:  
       Student Info:   
  ID:981036   
  Name:LiuMing   
  Age:18   
  Passw:123456  

从上面的代码,我们可以看到对Student对象实例序列化后保存到data.ser中,然后读取该文件获取到原对象的信息。



三、---transient---



串行化可能涉及将对象存放到 磁盘上或在网络上发达数据,这时候就会产生安全问题。因为数据位于Java运行环境之外,不在Java安全机制的控制之中。对于这些需要保密的字段,不应保存在永久介质中 ,或者不应简单地不加处理地保存下来 ,为了保证安全性。应该在这些字段前加上transient关键字。

在有些情况下,是不希望对象的所有成员变量都进行序列化,比如Student中的passwd字段,这个是敏感数据,不希望它被序列

化,那么就可以使用transient关键字。transient,顾名思义,非持久化的。使用transient关键字修饰成员变量,能够使它在序列化的

过程中被忽略。



四、---自定义序列化---



可以使用writeObjectreadObject方法来实现自定义序列化。在通过ObjectOutputStreamwriteObject方法写入对象的时候,如果这个对象

的类中定义了writeObject方法,就会调用该方法,并把当前 ObjectOutputStream对象作为参数传递进去。writeObject方法中一般会包含自

定义的序列化逻辑,比如在写入之前修改域的值,或是写入额外的数据等。

如下是自定义序列化的例子,注意是private类型,如下:

    transient private String passwd;

    private void writeObject(ObjectOutputStream out) throws IOException 
    {
        out.defaultWriteObject();
        out.writeObject("new_passwd");
    }
通过上面的方式就可以实现密码的改变密码为new_passwd,其中defaultWriteObject()是默认的序列化操作,所以我们在自定序列

之前首先要先默认序列化的操作。



五、---Externalizable---




地方以上例子都是基于实现Serializable接口来实现序列化的,Externalizable接口继承于Serializable,通过实现Externalizable接口也能

实现序列化,不同的是,序列化操作的细节需要自己实现,而且,必须提供public的无参构造函数

package ThreeWeek;

import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class Test 
{

    public static void main(String[] args)
    {
        File file = new File("user.out");
        User user = new User("Jack", "123456", 20);

        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
            out.writeObject(user);
            out.close();

            ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
            Object object = in.readObject();
            System.out.println(object);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}



class User implements Externalizable
{
    private String name;
    private String passwd;
    private int age;

    public User(String name, String passwd, int age) {
        this.name = name;
        this.passwd = passwd;
        this.age = age;
    }

    public User()
    {
        System.out.println("no arguments constructor");
    }

    public String toString()
    {
        return "[" + name + ", " + passwd + ", " + age + "]";
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException 
    {
        out.writeObject(name);
        out.writeObject(passwd);
        out.writeInt(age);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException 
    {
        name = (String) in.readObject();
        passwd = (String) in.readObject();
        age = in.readInt();
    }
}
通过上面的代码我们可以看出,在Externalizable中具体的写入和读出的方法需要自己来实现。

采用这种方法实现序列化,transient是不起作用的,如果你不想序列化某个成员变量,只要在readExternalwriteExternal中不对该变量进行相应操作就可以了。



尊重作者,尊重原创,参考文章:

http://www.jianshu.com/p/56671a839f9c

http://blog.csdn.net/jzhf2012/article/details/8538977



你可能感兴趣的:(java,Serializable,se,对象序列化)