序列化与反序列化

序列化与反序列化

什么是序列化?什么是反序列化?

序列化: 将对象写入对象输出流中

反序列化:从对象输入流中读出对象

为什么需要序列化?

对象传输数据复杂,类与类之间有关联,比如继承或者引用,序列化机制可以通过对象图机制读写对象,以满足复杂对象的关联,如单链表。实际上,这是动态保存了对象的状态。

怎么实现序列化?

java类库提供很多IO类支持不同需求的IO操作。首先介绍自动序列化,自动序列化需要被传输的类实Serializable接口,此类中引用到的类也需要实现这个接口,接口虽然是空实现,但是必须实现才能被jvm认可可序列化。反序列化时会调用无参构造

自动序列化

Parent类
public class Parent implements Serializable {

    private Son son;
//    private transient Son son;

    private String name;

    public Parent(Son son, String name) {
        this.son = son;
        this.name = name;
    }

    public Parent() {
    }

    public Son getSon() {
        return son;
    }

    public void setSon(Son son) {
        this.son = son;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Parent{" +
                "son=" + son +
                ", name='" + name + '\'' +
                '}';
    }
}
Son类
public class Son implements Serializable {

    private int age;

    private String name;

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

    public Son() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Son{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
Client类
public class Client {
    public static void main(String[] args) {
        Son son = new Son(11,"小小");
        Parent parent = new Parent(son,"大大");

        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("data.dat"));
            in = new ObjectInputStream(new FileInputStream("data.dat"));

            out.writeObject(parent);
            Parent p = (Parent)in.readObject();
            System.out.println(p);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
//打印 : Parent{son=Son{age=11, name='小小'}, name='大大'}

那么,如果我们不希望Son也被序列化,即只需要parent的其他成员有状态,我们可以添加关键字transient,如同Person类的注释,此时Son类也可以不实现序列化接口,打印如

Parent{son=null, name='大大'}

自定义序列化

自动序列化有些需求无法完成,我们可以使用自定义序列化。可以扩展序列化时的处理,比如对密码加密、解密···

class MD6{
    public static String md(String s){
        return "加密操作"+s;
    }
    public static String emd(String s){
        return s.substring(4,s.length());
    }
}


class Parent1 implements Externalizable {

    private String username;

    private String pwd;

    public Parent1(String username, String pwd) {
        this.username = username;
        this.pwd = pwd;
    }
    public Parent1(){}

    @Override
    public String toString() {
        return "Parent1{" +
                "username='" + username + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(username);
        String md = MD6.md(pwd);
        out.writeObject(md);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        username = (String)in.readObject();
        String s = (String)in.readObject();
        pwd = MD6.emd(s);
    }
}
class App11{
    public static void main(String[] args) {
        Parent1 p = new Parent1("小王","123456");
        ObjectOutputStream out = null;
        ObjectInputStream in = null;

        try {
            out = new ObjectOutputStream(new FileOutputStream("data1.dat"));
            in = new ObjectInputStream(new FileInputStream("data1.dat"));

            out.writeObject(p);
            Parent1 pp = (Parent1)in.readObject();
            System.out.println(pp);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

实际上,我们不要局限于加密解密,我这里写得很简单,实际上这些“加解密”操作我们都是可以扩展延伸的。

半自动自定义序列化

使用transient关键字修饰需要特殊处理的成员,序列化特殊处理实现两个私有方法,writeObject,readObject,JVM调用对象流默认调用类中相应的私有方法,在这两个方法中调用默认的序列化操作,和特殊处理手动序列化的值。毫无疑问这更加方便。至于为什么JVM为什么会这样调用方法,之后学习到更深层再解答。

class MD6{
    public static String md(String s){
        return "加密操作"+s;
    }
    public static String emd(String s){
        return s.substring(4,s.length());
    }
}
 class Parent2 implements Serializable {
    private String username;

    private transient String pwd;

    public Parent2(String username, String pwd) {
        this.username = username;
        this.pwd = pwd;
    }
    public Parent2(){}

    @Override
    public String toString() {
        return "Parent2{" +
                "username='" + username + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }

    private void writeObject(ObjectOutputStream out) throws IOException{
        out.defaultWriteObject();
        String md = MD6.md(pwd);
        out.writeObject(md);
    }

    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
        in.defaultReadObject();
        String s= (String)in.readObject();
        pwd = MD6.emd(s);
    }

}

class App21{
    public static void main(String[] args) {
        Parent2 p = new Parent2("小王","1234256");
        ObjectOutputStream out = null;
        ObjectInputStream in = null;

        try {
            out = new ObjectOutputStream(new FileOutputStream("data1.dat"));
            in = new ObjectInputStream(new FileInputStream("data1.dat"));

            out.writeObject(p);
            Parent2 pp = (Parent2)in.readObject();
            System.out.println(pp);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值