深入浅出Java之Serializable接口

什么是对象的序列化?什么是对象的反序列化?序列化有什么用?单例模式下如何避免序列化的作用?……通过以下的文章你会得到你想要的答案!

===================================================
1.序列化的定义
百度百科上是这样定义序列化的:将对象的状态信息转换成可存储或者可传输的形式的过程。
通俗的讲就是,把你内存中的对象转换成字节码,以便于持久性储存或进行远程的数据交换。
2.反序列化的定义
就是把序列化倒回去,从你储存或者是接收到的对象字节码中,还原出序列化时状态的对象。
3.序列化有什么用
序列化能使对象信息持久化。(当你的应用退出时,你想让用户下次打开时可以继续上一次的操作。或者是你写的小游戏需要实现“继续游戏“的功能。……)
还能进行远程的对象信息传输。(我曾做过一个小型的群聊天室,客户端发送聊天消息给服务器端,由服务器端将消息转发给其他用户。在发送消息时,我们需要知道这个消息的发送时间、发送人、消息内容。我只能把这他们三个封装到一个Message类中,让Message的对象实现信息传输。)

简单的向硬盘上存储对象信息:

private void store() throws Exception{
        ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("F:/codeTemp/object.out"));
        Msg msg =new Msg();
        //set content 、person、date
        oos.writeObject(msg);
        oos.flush();
        oos.close();
    }

简单的使用Socket通信中的OutputStream实现对象信息的传输:

/**
 * send message
 * @param os --the OutputStream get from socket 
 * @throws Exception
 */
private void sendMsg(OutputStream os) throws Exception{
        ObjectOutputStream oos =new ObjectOutputStream(os);
        Msg msg= new Msg();
        //设置内容
        //设置日期
        //设置消息的发送人
        oos.writeObject(msg);
        oos.flush();
        oos.close();
}

简单的从硬盘中读取对象信息

private Msg getStore() throws Exception{
        ObjectInputStream ois =new ObjectInputStream(new FileInputStream("F:/codeTemp/object.out"));
        Msg msg = (Msg)ois.readObject();
        return msg;
    }

简单的从socket通信中获取对象信息:

    /**
     * @param is --the inputstream from socket
     * @return  get message
     * @throws Exception
     */
    public static Msg getMsg(InputStream is) throws Exception{
        ObjectInputStream ois =new ObjectInputStream(is);
        Msg msg = (Msg)ois.readObject();
        return msg;
    }

说了这么多,和我们要探讨的序列化接口Serializable好像没什么关系啊?
注意,我们的序列化对象Msg必须实现Serializable。否则会抛出NotSerializableException

===================================================

序列化时,你必须要知道的几点:
1.静态成员是类级别的,他不会被序列化。所以,我们不能序列化static修饰的变量
2.Java中还为序列化定义了一个相关的变量修饰符—transient。被transient修饰的变量不会参与序列化
3.序列化的对象中有引用型变量时,引用变量也会被序列化。依次递归序列化
4.子类继承了可序列化的父类时,子类就可以被序列化。
5.除了使用Serializable接口,我们还可以使用Externalizable接口,但是我们必须自己去实现序列化的过程,即需要重写writeExternal(ObjectOutput out)和readExternal(ObjectInput in)这两个未实现的方法。
6.序列化中的一个非常重要的概念,序列化ID。 private static final long serialVersionUID = 1L。
7.向Object流中写对象时,若对象已经存在,则不会将对象再次进行写入,而是进行引用的写入。
8.-7的这条原则同样适用于硬盘的存储对象,java为了节省磁盘空间,不会进行重复的对象写入。

==================================================
了解java设计模式的人一定会知道,单例模式要避免序列化的来的影响。

反序列化出来的对象是原对象的深拷贝
看如下的代码:

//单例类
public class Singleton implements Serializable {
        private String name = null;
        private Integer age = null;
        private static final Singleton instatnce = new Singleton("John", 31);

        public static Singleton getInstance() {
            return instatnce;
        }

        private Singleton() {}

        private Singleton(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
}
//测试单例类的序列化
    public static void main(String args[]) throws Exception {
        Singleton obj = Singleton.getInstance();

        /*write obj to a file*/
        ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("F:/codeTemp/object.out"));
        oos.writeObject(obj);
        oos.flush();
        oos.close();

        /*read obj from a file*/
        ObjectInputStream ois =new ObjectInputStream(new FileInputStream("F:/codeTemp/object.out"));
        Singleton readObj= (Singleton) ois.readObject();

        /*judge the two Object is or is not same one */
        System.out.println("obj ?== readObj:"+(obj==readObj));
    }

结果

obj ?== readObj:false

这就说明了反序列化出来的对象是原对象的深拷贝。

要想保持单例,我们就需要添加一个readSolve()方法,直接返回单例对象。
在io的反序列化过程中,无论是实现了Serializable接口还是实现Externalizable接口,都会调用readSolve()方法。我们若是让readSovle返回对象,那么反序列化创建的对象就不会被返回了。

//实现了readSovle()方法的单例类
public class Singleton implements Serializable {
        private String name = null;
        private Integer age = null;
        private static final Singleton instatnce = new Singleton("John", 31);

        public static Singleton getInstance() {
            return instatnce;
        }

        private Singleton() {}

        private Singleton(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        private Object readResolve() throws ObjectStreamException {
            return instatnce;
        }
}

重新测试一下单例类,结果:

obj ?== readObj:true

以上只是序列化的简单介绍,以后会追加更深层次的介绍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值