java-序列化

1、实现 Serializable 接口,默认的序列化方式

2、实现 Externalizable  接口,这个接口要实现两个方法
    void writeExternal(ObjectOutput var1) throws IOException;
    void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException;
    分别在调用序列化和反序列化的时候进行调用。这样就可以自己定制自己的序列化方式,如加密后序列化,某个属性不用序列化(transient 也可以实现)

public class SerrializableTest implements Externalizable{

    private String name;
    private int age;
    private String email;

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("write");
		//write 和read 要顺序一致
        out.writeObject(email);
        out.writeInt(age);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        System.out.println("read");
		//write 和read 要顺序一致
        this.email = (String)in.readObject();
        this.age = in.readInt();
    }

    public static void main(String[] args)  throws IOException,SecurityException,ClassNotFoundException{

        String filePath = "a";

        SerrializableTest t = new SerrializableTest("mayihan",1,"mail");
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ObjectOutputStream  o = new ObjectOutputStream(new FileOutputStream(new File(filePath)));
        o.writeObject(t);
		o.flush();
        o.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(filePath)));
        SerrializableTest tt = (SerrializableTest)in.readObject();
        System.out.println(tt);
    }

    @Override
    public String toString() {
        return name+"--"+age+"-"+email;
    }

    public SerrializableTest(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }

    /**
     * 必须要有默认的构造器
     */
    public SerrializableTest() {
    }
}
输出:
write
read
null--1-mail

上面代码中只序列化了age 和 email,可以在实现接口方法中添加加密解密的实现等,就添加了功能实现。
注意:必须要有默认的构造器。

与Serializable 区别:
 Serializable 反序列化是用二进制位来构造的,不要调用构造器。而Externalizable所有普通的置信构造器都会被调用(包括在字段定义时的初始化),然后调用readExternal 方法。

3、transient
Serializable 默认所有的属性都会被序列化,Externalizable 要自己手动序列化不会自动序列化。当在操作 Serializable  对象时,可以使用transient 关键字关闭某个属性,意思说:不用自动序列化和恢复,自己手动处理。上面的手动序列化就实现了transient 实现。


4、实现Serializable接口,实现手动序列化。
     实现Serializable接口后,添加方法(主意方法是私有的):

  /**
     * 添加 序列化方法
     * @param outputStream
     * @throws IOException
     */
    private void writeObject(ObjectOutputStream outputStream) throws IOException{}


    /**
     * 添加反序列化方法
     * @param inputStream
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void readObject(ObjectInputStream inputStream) throws IOException,ClassNotFoundException{}
在调用序列化、反序列化时这两个方法会被调用(方法是私有的,后面通过反射 实现调用私有方法)。
示例:

public class SerrializableTest implements Serializable{

    private String name;
    private int age;
    private String email;
    /**
     * 添加 序列化方法
     * @param outputStream
     * @throws IOException
     */
    private void writeObject(ObjectOutputStream outputStream) throws IOException{
        System.out.println("write object");
        //write 和read 要顺序一致
        outputStream.writeInt(age);
        outputStream.writeObject(email);
    }

    /**
     * 添加反序列化方法
     * @param in
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{
        System.out.println("read object");
        //write 和read 要顺序一致
        this.age = in.readInt();
        this.email = (String)in.readObject();
    }

    public static void main(String[] args)  throws IOException,SecurityException,ClassNotFoundException{

        String filePath = "a";

        SerrializableTest t = new SerrializableTest("mayihan",1,"mail");
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ObjectOutputStream  o = new ObjectOutputStream(new FileOutputStream(new File(filePath)));
        o.writeObject(t);
		o.flush();
        o.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(filePath)));
        SerrializableTest tt = (SerrializableTest)in.readObject();
        System.out.println(tt);
    }

    @Override
    public String toString() {
        return name+"--"+age+"-"+email;
    }

    public SerrializableTest(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
}
运行结果,name 没有序列 :
write object
read object
null--1-mail
还有一点是:在writeObject(ObjectOutputStream outputStream) 中调用 outputStream.defaultWriteObject(); 方法,就又实现了默认的序列化。

/**
     * 添加 序列化方法
     * @param outputStream
     * @throws IOException
     */
    private void writeObject(ObjectOutputStream outputStream) throws IOException{
        System.out.println("write object");
        //使用默认输出方式
        outputStream.defaultWriteObject();
    }

    /**
     * 添加反序列化方法
     * @param inputStream
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void readObject(ObjectInputStream inputStream) throws IOException,ClassNotFoundException{
        System.out.println("read object");
        //使用默认输入方式
        inputStream.defaultReadObject();
    }
上面两个方法被定义成私有了,是在什么时候调用的呢?   通过debug 方式来查看
主要是通过反射来实现的,主要代码是在ObjectOutputStream.invokeWriteObject 方法,代码如下:
        
void invokeWriteObject(Object obj, ObjectOutputStream out)
        throws IOException, UnsupportedOperationException
    {
        requireInitialized();
        if (writeObjectMethod != null) {
            try {
                writeObjectMethod.invoke(obj, new Object[]{ out });
            } catch (InvocationTargetException ex) {
                Throwable th = ex.getTargetException();
                if (th instanceof IOException) {
                    throw (IOException) th;
                } else {
                    throwMiscException(th);
                }
            } catch (IllegalAccessException ex) {
                // should not occur, as access checks have been suppressed
                throw new InternalError(ex);
            }
        } else {
            throw new UnsupportedOperationException();
        }
    }
解析:
运行到此处:writeObjectMethod 就是自定义的writeObject 方法。
obj 就是当前要序列化的对象
out 就是输出





猜你喜欢

转载自blog.csdn.net/convict_eva/article/details/79206452
今日推荐