Java对象序列化

来源:互联网 发布:张大奕淘宝店 编辑:程序博客网 时间:2024/05/22 05:06


一、---概念---



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



1 0
原创粉丝点击