博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Serializable:序列化代理
阅读量:6293 次
发布时间:2019-06-22

本文共 4104 字,大约阅读时间需要 13 分钟。

序列化代理简单来说,A有序列化的需求,但是不直接序列化A,而是序列化一个A的代理对象B,我们可以将A的信息保存在B中,在反序列化时,再通过B得到A的信息,实例化一个A对象

为什么这么费劲呢?因为反序列化是机制之外的东西,不通过构造方法生成实例,这样有机会被入侵(具体说不上,就是有可能被黑的意思吧),采用序列化代理可以有效的避免通过反序列化来生成实例,所有的实例都通过构造函数来生成,这样就可以保证所有的实例都遵守构造函数的约束。
具体实现呢 通过例子来说吧:

package test3;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;/** * 1. 序列化Dog时, 会调用调用writeReplace()生成一个DogProxy对象, 然后对此对象进行序列化 (不是对Dog类对象进行序列化, *      由序列化文件的内容可以得知, 可以查看序列化生成的文件, 文件中内容为如下图 (代码之后的图) * 2. 反序列化时, 会调用DogProxy的readResolve()方法生成一个Dog对象,  *      最后返回此对象的拷贝 (通过DogProxy类的readResolve方法和main方法中的输出可以看出) * 3. 因此, Dog类的序列化工作完全交给DogProxy类, 正如此模式的名称所表达的一样 */public class Dog implements Serializable{    private static final long serialVersionUID = -8424740460257438938L;        private String name;    private int age;        public Dog(String name,int age) {        //约束条件        if(age < 0 || age > 100) {            throw new IllegalArgumentException("非法年龄");        }        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    /** 序列化代理内部类 */    private static class DogProxy implements Serializable{        private static final long serialVersionUID = -8883457811799334207L;        private String name;        private int age;        public DogProxy(Dog dog) {            this.name = dog.getName();            this.age = dog.getAge();        }                /** 反序列化时, 替换返回的对象(比喻偷天换日吧) */        private Object readResolve() {            return new Dog(name,age);        }        /** 自定义序列化形式 */        private void writeObject(ObjectOutputStream out) throws IOException {            out.defaultWriteObject();            System.out.println("SerializationProxy writeObject, 调用");        }        /** 自定义反序列化形式 */        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {            in.defaultReadObject();            System.out.println("SerializationProxy readObject, 调用");        }            }    /** 序列化时, 把this=Dog对象替换为序列化代理对象 */    private Object writeReplace() {        return new DogProxy(this);//readObject的时候是调用, DogProxy的readResolve()    }    /** 此方法不会执行 */    private void writeObject(ObjectOutputStream out) {        System.out.println("Dog writeObject, 不会调用");    }        /** 防止攻击者伪造数据, 企图违反约束条件 (如: 违反年龄约束) */    private void readObject(ObjectInputStream in) throws Exception {        throw new Exception("proxy required");    }    }

定义了一个内部类,DogProxy 作为Dog 的序列化代理

如果试图序列化一个Dog,由于Dog中定义了

private Object writeReplace() {        return new DogProxy(this);    }

则实际会序列化一个Dog的序列化代理,而这个序列化代理是通过Dog对象来构造的(保存了Dog的信息),上节说到,之后的过程都会依赖实际被序列化类的序列化实现,也就是会依赖于Dog序列化代理的序列化实现,反序列化Dog序列化代理时由于

private Object readResolve() {            return new Dog(name,age);        }

实际会返回一个Dog对象,这样原来保存的Dog信息又回来了,而且新的Dog实例是通过构造方法生成的。

如何使用呢,其实完全看不出来,正常用就行了

package test3;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;public class Test {    public static void main(String[] args) throws IOException, ClassNotFoundException {        Dog dog = new Dog("小白",12);        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:\\temp"));        out.writeObject(dog);        out.flush();        out.close();                        ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:\\temp"));        Dog deserDog = (Dog)in.readObject();        in.close();                System.out.println(deserDog.getAge());        System.out.println(deserDog.getName());                if(dog == deserDog) {            System.out.println("序列化前后是同一个对象");        } else {            //程序会走这一段, 反序列化会创建对象, 但是不会执行类的构造方法, 而是使用输入流构造对象            System.out.println("序列化前后不是同一个对象, 哈哈哈");        }            }    }

用法呢其实都是相同的,关键是序列化类wirteObject和readObject的实现。

转载于:https://www.cnblogs.com/gscq073240/articles/6930469.html

你可能感兴趣的文章
PHP中常见的面试题2(附答案)
查看>>
26.Azure备份服务器(下)
查看>>
mybatis学习
查看>>
LCD的接口类型详解
查看>>
Spring Boot Unregistering JMX-exposed beans on shutdown
查看>>
poi 导入导出的api说明(大全)
查看>>
Mono for Android 优势与劣势
查看>>
将图片转成base64字符串并在JSP页面显示的Java代码
查看>>
js 面试题
查看>>
sqoop数据迁移(基于Hadoop和关系数据库服务器之间传送数据)
查看>>
腾讯云下安装 nodejs + 实现 Nginx 反向代理
查看>>
Javascript 中的 Array 操作
查看>>
java中包容易出现的错误及权限问题
查看>>
AngularJS之初级Route【一】(六)
查看>>
服务器硬件问题整理的一点总结
查看>>
SAP S/4HANA Cloud: Revolutionizing the Next Generation of Cloud ERP
查看>>
Mellanox公司计划利用系统芯片提升存储产品速度
查看>>
白帽子守护网络安全,高薪酬成大学生就业首选!
查看>>
ARM想将芯片装进人类大脑 降低能耗是一大挑战
查看>>
Oracle数据库的备份方法
查看>>