zoukankan      html  css  js  c++  java
  • 自定义序列化小记

    对于实现了Serializable接口的类,在对其对象进行序列化的时候,会自动将该对象的所有实例变量依次进行序列,特别是在某个实例变量应用到了其他对象时,表现为递归式的序列化机制。这种“一概而全”序列化方式往往不是我们实际想要的,因此有必以自定义的方式来序列化(具体地讲比如控制某些实例变量可以序列化,增加一些处理逻辑进行序列化等等)。有以下几种方式来实现自动以的序列化。

    1、使用transient关键字

    使用transient关键字修饰实例变量。从语义上讲transient是短暂的、瞬态的意思,因此不适合用序列化策略来存储。在序列化的时候该实例变量不会被写进字节序列,相当于会忽略掉该变量的序列化。这是最简单方便的自定义序列化方式,在JDK源码中也有很多地方用到了该关键字来修饰的实例变量。

    使用transient关键字实现自定义序列化有几件事需要了解:

    a、transient只应该用来修饰成员变量,不应修饰类变量。虽然在语法上用transient修饰静态变量不会报错,但是这样做没有效果也没有意义:类变量本身就是隶属于类,不属于任何一个对象。

    b、反序列化后,之前被transient修饰的变量的值被赋予系统设定的默认初值(同时注意:反序列化的过程不会调用对象的任何构造器)。

    c、实现了Externalizable接口

    package com.prac;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    
    public class TestSeri{
        public static void main(String[] args) {
            String path = System.getProperty("user.dir")+"\target.md";
            Target target = new Target("hi");
            try {
                //序列化
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
                oos.writeObject(target);
                //反序列化
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
                Target othetarget = (Target)ois.readObject();
    
                Target.staticVar += " world!";//改变Target类的静态变量
            
                System.out.println("instVar = "+othetarget.instVar);
                //输出了"hello world!",静态变量不参与序列化
                System.out.println("staticVar = "+othetarget.staticVar);
                
                //以下成员变量未参与序列化,反序列化后赋予系统设定的初始值
                System.out.println("intValue = "+othetarget.intValue);//0
                System.out.println("doubleValue = "+othetarget.doubleValue);//0.0
                System.out.println("booValue = "+othetarget.booValue);//fasle
                System.out.println("stringValue = "+othetarget.stringValue);//null
                System.out.println("objValue = "+othetarget.objValue);//null
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }
    class Target implements Serializable{
        public static String staticVar = "hello";
    //    public transient static String staticValue = "hello";//语法上可以用transient修饰静态变量,但无意义
        public String instVar = ""; 
        
        public transient double doubleValue = 10.0;
        public transient int intValue = 100;
        public transient boolean booValue = true;
        public transient String stringValue = "hello world";
        public transient Object objValue = new Object();
        public Target(){
            System.out.println("invoke Target()");
        }
        public Target(String instVar){
            this.instVar = instVar;
            System.out.println("invoke Target(String instVar)");
        }
    }

    2、使用特殊签名的方法

    在类中定义如下三个特殊签名的方法,可以按照自定义的逻辑来实现自定义序列化。

    private void writeObject(ObjectOutputStream oos) throws IOException
    private void readObject(ObjectInputStream ois) throws IOException,ClassNotFoundException
    private void readObjectNoData() throws ObjectStreamException

    一个简单的示例如下:

    package com.prac;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    
    public class TestSeri{
        public static void main(String[] args) {
            String path = System.getProperty("user.dir")+"\target.md";
            User user = new User("qcer","123456");
            try {
                //序列化
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
                oos.writeObject(user);
                //反序列化
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
                User otheuser = (User)ois.readObject();
                
                System.out.println("username = "+otheuser.username);
                System.out.println("password = "+otheuser.password);
    
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }
    class User implements Serializable{
        public String username = "";
        public String password = "";
        public User(){
        }
        public User(String username,String password){
            this.username = username;
            this.password = password;
        }
        private void writeObject(ObjectOutputStream oos) throws IOException{
            oos.writeObject(username);
            oos.writeObject(encrypt(password));
        }
        private void readObject(ObjectInputStream ois) throws IOException,ClassNotFoundException{
            this.username = (String)ois.readObject();
            this.password = dencrypt((String)ois.readObject());
        }
        private String encrypt(String plaintext){
            String ciphertext = "";
            //...省略加密算法部分
            return ciphertext;
        }
        private String dencrypt(String ciphertext){
            String plaintext = "";
            //...省略解密算法部分
            return plaintext;
        }
    }

    3、实现Externalizable接口

     Externalizable实接口际上是继承了Serializable接口

    实现Externalizable接口的类中需要实现writeExternal(ObjectOutput out)和readExternal(ObjectInput in)两个方法,同之前的一样,可以用out.writeXXX()和in.readXXX()的方式来自定义序列化和反序列化数据。

    一个示例如下:

    package com.prac;
    
    import java.io.*;
    public class TestExseri{
        public static void main(String[] args) {
            String path = System.getProperty("user.dir")+"\book.md";
            Book book = new Book("Thinking in Java",108.00);
            try {
                //序列化
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
                oos.writeObject(book);
                //反序列化,会调用Book类的无参构造器
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
                Book otherbook = (Book)ois.readObject();
                
                System.out.println("name = "+otherbook.name);//Thinking in Java
                System.out.println("price = "+otherbook.price);//108.0
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }
    class Book implements Externalizable{
        public transient String name = "";
        public double price = 0.0;
        public Book(){
            System.out.println("invoke Book()");
        }
        public Book(String name,double price) {
            this.name = name;
            this.price = price;
        }
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeObject(name);
            out.writeDouble(price);
        }
        @Override
        public void readExternal(ObjectInput in) throws IOException,
                ClassNotFoundException {
            this.name = (String)in.readObject();
            this.price = in.readDouble();
        }
    }

    实际上,ObjectOutputStream实现了ObjectOutput接口,而后者继承了DataOutput接口。

  • 相关阅读:
    《程序员成长的烦恼》
    我们一起读《暗时间》
    CSS选择器分类总结
    CSharp如何自定义鼠标样式
    Android开发消除横向排列的多个Button之间的空隙
    JS代码指导原则
    Android蓝牙联机Demo解析
    排序算法之堆排序(Heapsort)解析
    排序算法之归并排序(Mergesort)解析
    经典串匹配算法(KMP)解析
  • 原文地址:https://www.cnblogs.com/qcblog/p/8094216.html
Copyright © 2011-2022 走看看