java序列化

java中的序列化

经常听到关于序列化的话题,但是一直没有理解什么是序列化,为什么要序列化。

首先百度了一下序列化的定义:序列化(Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入临时或持久性存储区。以后可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

在java中,存在于java虚拟机中的对象,他的内部状态只保存在内存中。如果jvm停止了这些状态就会丢失。在java中实现基本的对象序列化是件很简单的事。需要序列化的java类只需要实现java.io.Serializable接口即可。这个接口只是作为一个标识,表示这个类可以进行序列化和反序列化。

序列化的特点:如果一个类能够被序列化,那么他的子类也可以被序列化。这里有个问题就是:如果子类需要序列化的话,还是要显式的声明serialVersionUID。在反序列化的时候声明为statictransient类型的成员变量不能被序列化。static表示类的状态,transient表示对象的临时数据。

序列化的运用场景:
1.需要把内存中的对象状态保存到一个文件或者数据库中。
2.需要使用套接字在网络传输对象。
3.需要使用RMI传输对象。
java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。当然这些属性对象也需要实现接口java.io.Serializable

实际的序列化和反序列化工作是通过ObjectOutputStreamObjectInputStream来完成。ObjectOutputStreamwriteObject方法可以把一个java对象写到流中。ObjectInputStreamreadObject方法可以从流中读取一个java对象。虽然用的参数或者返回值都是单个对象,但是实际操作的是一个对象图。包括了这个对象状态所引用的其他对象,以及具有相关关系的对象。会自动遍历这个对象图逐个序列化。基本数据类型和数组也是可以通过他们序列化的。

serialVersionUID序列化版本号。
序列化运行时使用了serialVersionUID与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。为了保证序列化版本号的一致性,序列化类需要声明一个明确的版本号值。

private static final long serialVersionUID = 1L;

serialVersionUID字段只是一个标识值。只用于当前这个类。

序列化机制:序列化分为两大部分:序列化和反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节 表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例。ObjectOutputStream中的序列化过程与字节流连接,包括对象类型和版本信 息。反序列化时,JVM用头信息生成对象实例,然后将对象字节流中的数据复制到对象数据成员中。

真正在需要序列化的时候都会根据实现的接口来进行操作。
当然也可以自己定义序列化的方法。

public interface Externalizable extends java.io.Serializable{}

一个类如果要完全负责自己的序列化,就可以实现Externalizable接口,自己实现里面的两个方法。利用这些方法可以控制对象数据成员如何写入字节流.类实现 Externalizable时,头写入对象流中,然后类完全负责序列化和恢复数据成员,除了头以外,根本没有自动序列化。这里要注意了。声明类实现 Externalizable接口会有重大的安全风险。writeExternal()与readExternal()方法声明为public,恶意类可 以用这些方法读取和写入对象数据。如果对象包含敏感信息,则要格外小心。

public class SerializerUtils {
    /**
     * 序列化
     * @param object
     * @return
     */
    public static byte[] serialize(Object object) {
        ObjectOutputStream objectOutputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(object);
            byte[] bytes = byteArrayOutputStream.toByteArray();
            return bytes;
        } catch (Exception e) {
            return null;
        } finally {
            if (objectOutputStream != null) {
                try {
                    objectOutputStream.close();
                } catch (IOException e) {
                    //ignore
                }
            }
            if (byteArrayOutputStream != null) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    //ignore
                }
            }
        }
    }
    /**
     *  反序列化
     */
    @SuppressWarnings("unchecked")
    public static <T> T unserialize(byte[] bytes) {
        ByteArrayInputStream byteArrayInputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            byteArrayInputStream = new ByteArrayInputStream(bytes);
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return (T) objectInputStream.readObject();
        } catch (Exception e) {
            return null;
        } finally {
            if (objectInputStream != null) {
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    //ignore
                }
            }
            if (byteArrayInputStream != null) {
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    //ignore
                }
            }
        }
    }
}

对象序列化成byte[]byte[]转换成对象方法。ObjectInputStreamObjectOutputStream将对象从流中取出和写入到流中。这里使用的是ByteArrayInputStreamByteArrayOutputStream作为容器然后�与byte[]进行相互转换。

在通过ObjectInputStreamreadObject方法读取到一个对象之后,这个对象是一个新的实例,但是其构造方法是没有被调用的,其中的�属性的初始化代码也没有被执行。对于那些没有被序列化的属性,在新创建出来的对象中的值都是默认的。也就是说,这个对象从某种角度上来说是不完备的。这有可能会造成一些隐含的错误。调用者并不知道对象是通过一般的new操作符来创建的,还是通过反序列化所得到的。解决的办法就是在类的readObject方法里面,再执行所需的对象初始化逻辑。对于一般的Java类来说,构造方法中包含了初始化的逻辑。可以把这些逻辑提取到一个方法中,在readObject方法中调用此方法。
如果序列化对象后,这个对象的类发生了改变,这时需要注意是否需要有兼容性。一般来说,在新的版本中添加东西不会产生什么问题,而去掉一些属性则是不行的。

java序列化与反序列化-ImportNew

Java对象序列化与RMI-infoQ

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • JAVA序列化机制的深入研究 对象序列化的最主要的用处就是在传递,和保存对象(object)的时候,保证对象的完整...
    时待吾阅读 10,741评论 0 24
  • 概念 序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。 这两个过程结...
    Moonsmile阅读 388评论 0 0
  • 如果你只知道实现 Serializable 接口的对象,可以序列化为本地文件。那你最好再阅读该篇文章,文章对序列化...
    jiangmo阅读 429评论 0 2
  • 一、序列化 java序列化提供了一个框架,用来将对象编码成字节流,并从字节流编码中重新构建的对象。将对象编码为字节...
    oneWeekOneTopic阅读 1,856评论 0 3
  • 正如前文《Java序列化心得(一):序列化设计和默认序列化格式的问题》中所提到的,默认序列化方法存在各种各样的问题...
    登高且赋阅读 8,126评论 0 19