`
wlh269
  • 浏览: 453376 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

序列化(二)

    博客分类:
  • J2SE
阅读更多
简单来说序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化,流的概念这里不用多说(就是I/O),我们可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间(注:要想将对象传输于网络必须进行流化)!在对对象流进行读写操作时会引发一些问题,而序列化机制正是用来解决这些问题的!

问题的引出:

如上所述,读写对象会有什么问题呢?比如:我要将对象写入一个磁盘文件而后再将其读出来会有什么问题吗?别急,其中一个最大的问题就是对象引用!举个例子来说:假如我有两个类,分别是A和B,B类中含有一个指向A类对象的引用,现在我们对两个类进行实例化{ A a = new A(); B b = new B(); },这时在内存中实际上分配了两个空间,一个存储对象a,一个存储对象b,接下来我们想将它们写入到磁盘的一个文件中去,就在写入文件时出现了问题!因为对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,这样的话当我们从文件中恢复对象时(也就是重新加载到内存中)时,内存分配了三个空间,而对象a同时在内存中存在两份,想一想后果吧,如果我想修改对象a的数据的话,那不是还要搜索它的每一份拷贝来达到对象数据的一致性,这不是我们所希望的!
以下序列化机制的解决方案:

1.保存到磁盘的所有对象都获得一个序列号(1, 2, 3等等)

2.当要保存一个对象时,先检查该对象是否被保存了。

3.如果以前保存过,只需写入"与已经保存的具有序列号x的对象相同"的标记,否则,保存该对象

通过以上的步骤序列化机制解决了对象引用的问题!

序列化的实现

将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

例子:

import java.io.*;

public class Test {
        public static void main(String[] args) {
                Employee harry = new Employee("Harry Hacker", 50000);
                Manager manager1 = new Manager("Tony Tester", 80000);
                manager1.setSecretary(harry);
                Employee[] staff = new Employee[2];
                staff[0] = harry;
                staff[1] = manager1;
                try {
                        ObjectOutputStream out = new ObjectOutputStream(
                                        new FileOutputStream("employee.dat"));
                        out.writeObject(staff);
                        out.close();
                        ObjectInputStream in = new ObjectInputStream(new FileInputStream(
                                        "employee.dat"));
                        Employee[] newStaff = (Employee[]) in.readObject();
                        in.close();

                        /**
                         * 通过harry对象来加薪 将在secretary上反映出来
                         */
                        newStaff[0].raiseSalary(10);
                        for (int i = 0; i < newStaff.length; i++)
                                System.out.println(newStaff[i]);
                } catch (Exception e) {
                        e.printStackTrace();

                }
        }
}

class Employee implements Serializable {
        public Employee(String n, double s) {
                name = n;
                salary = s;
        }
        /**
         * 
         * 加薪水
         * 
         */
        public void raiseSalary(double byPercent) {
                double raise = salary * byPercent / 100;
                salary += raise;
        }

        public String toString() {
                return getClass().getName() + "[name = " + name+ ",salary = " + salary+ "]";
        }
        private String name;
        private double salary;
}

class Manager extends Employee

{
        public Manager(String n, double s)
        {
                super(n, s);
                secretary = null;
        }
        /**
         * 
         * 设置秘书
         * 
         */
        public void setSecretary(Employee s)
        {
           secretary = s;
        }
        
        public String toString()
        {
                return super.toString()+ "[secretary = " + secretary+ "]";
        }

        // secretary代表秘书

        private Employee secretary;

}

修改默认的序列化机制

在序列化的过程中,有些数据字段我们不想将其序列化,对于此类字段我们只需要在定义时给它加上transient关键字即可,对于transient字段序列化机制会跳过不会将其写入文件,当然也不可被恢复。但有时我们想将某一字段序列化,但它在SDK中的定义却是不可序列化的类型,这样的话我们也必须把他标注为transient,可是不能写入又怎么恢复呢?好在序列化机制为包含这种特殊问题的类提供了如下的方法定义:

private void readObject(ObjectInputStream in) throws

IOException, ClassNotFoundException;

private void writeObject(ObjectOutputStream out) throws

IOException;

(注:这些方法定义时必须是私有的,因为不需要你显示调用,序列化机制会自动调用的)

使用以上方法我们可以手动对那些你又想序列化又不可以被序列化的数据字段进行写出和读入操作。

下面是一个典型的例子,java.awt.geom包中的Point2D.Double类就是不可序列化的,因为该类没有实现Serializable接口,在我的例子中将把它当作LabeledPoint类中的一个数据字段,并演示如何将其序列化!

import java.io.*;

import java.awt.geom.*;

public class TransientTest

{

        public static void main(String[] args)
        {
                LabeledPoint label = new LabeledPoint("Book", 5.00, 5.00);
                try
                {
                        System.out.println(label);// 写入前
                        ObjectOutputStream out = new ObjectOutputStream(new
                        FileOutputStream("Label.txt"));
                        out.writeObject(label);
                        out.close();
                        System.out.println(label);// 写入后
                        ObjectInputStream in = new ObjectInputStream(new
                        FileInputStream("Label.txt"));
                        LabeledPoint label1 = (LabeledPoint) in.readObject();
                        in.close();
                        System.out.println(label1);// 读出并加1.0后
                }
                catch (Exception e)
                {
                        e.printStackTrace();
                }
        }
}

class LabeledPoint implements Serializable
{
        public LabeledPoint(String str, double x, double y)
        {
                label = str;
                point = new Point2D.Double(x, y);
        }

        private void writeObject(ObjectOutputStream out) throws IOException
        {
                /**
                 * 
                 * 必须通过调用defaultWriteObject()方法来写入
                 * 
                 * 对象的描述以及那些可以被序列化的字段
                 * 
                 */

                out.defaultWriteObject();
                out.writeDouble(point.getX());
                out.writeDouble(point.getY());
        }

        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
        {
                /**
                 * 
                 * 必须调用defaultReadObject()方法
                 * 
                 */
                in.defaultReadObject();
                double x = in.readDouble() + 1.0;
                double y = in.readDouble() + 1.0;
                point = new Point2D.Double(x, y);

        }

        public String toString()
        {
                return getClass().getName()+ "[label = " + label+ ", point.getX() = " + point.getX()+ ", point.getY() = " + point.getY()+ "]";
        }
        private String label;
        transient private Point2D.Double point;
}
分享到:
评论

相关推荐

    二进制序列化和XML序列化

    在.NET框架中,有两种常见的序列化方式:二进制序列化和XML序列化。这两种方法各有优缺点,适用于不同的场景。 一、二进制序列化 二进制序列化是.NET框架提供的一种高效的数据序列化方式,它将对象转换为字节流,以...

    二进制BinaryFormatter进行序列化与反序列化

    ### 二进制序列化与反序列化 #### 一、概述 在.NET框架中,序列化是一项重要的功能,它允许开发人员将对象的状态转换成一种可以存储或传输的形式。通常,序列化有两种主要实现方式:**二进制序列化**(通过`...

    delphi 序列化

    序列化 (serialization):将对象的状态信息转换为可以存储或传输的形式的过程。 与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。 序列化的目的  1、以某种存储形式使...

    C#序列化实例讲解,C#序列化实例源代码

    C#提供了多种序列化机制,如XML序列化、二进制序列化、JSON序列化等,每种都有其特定的应用场景。 二、XML序列化 XML序列化将对象转换为XML格式的字符串,易于阅读和交换。在C#中,可以使用`XmlSerializer`类实现...

    base64序列化字符串

    - **JSON数据**:序列化二进制数据,使其能在JSON格式中传输。 - **文件存储**:将文件内容编码为Base64字符串,存储在数据库或其他文本文件中。 ### 7. 文件名列表中的"DeserializeStr" 在给定的压缩包文件中,...

    C#自定义可序列化的Dictionary类型

    C#自定义可序列化的Dictionary类型 在C#中,Dictionary类型是非常常用的数据结构,但是.NET 2.0中的泛型Dictionary却不支持XML序列化。这是一种非常不便的限制,因为在实际应用中,我们经常需要将数据序列化到XML...

    c#序列化和反序列化

    #### 二、反序列化概述 反序列化是将序列化后的数据恢复成对象的过程。它允许我们在读取存储的数据或接收远程传输的数据之后,能够重新构建原始对象的状态。 **为什么需要反序列化?** - **恢复对象状态**:在数据...

    C#和Java的序列化反序列化

    在C#中,我们可以使用.NET框架提供的`System.Runtime.Serialization.Formatters.Binary.BinaryFormatter`类来进行二进制序列化,或者使用`System.Xml.Serialization.XmlSerializer`来进行XML序列化。而在Java中,...

    C++ JSON 序列化与反序列化

    **二、JSON反序列化** 反序列化是将JSON字符串恢复为C++对象的过程。继续以nlohmann/json为例: 1. 从JSON字符串创建json对象: ```cpp std::string jsonString = R"({"name":"John","age":30})"; json j = json::...

    hessian学习基础篇——序列化和反序列化

    本文将深入探讨Hessian框架的基础知识,它是一个高效的二进制序列化协议,广泛应用于Java和.NET之间跨语言通信。通过学习Hessian,我们可以更有效地处理数据传输,提高应用性能。 首先,让我们理解什么是序列化。...

    C#中二进制数组转换,二进制序列化和json序列化方法

    本篇将深入探讨如何在C#中进行二进制数组与常规数组之间的转换,以及二进制序列化和JSON序列化的应用及其反序列化过程。 首先,让我们来看看二进制数组与常规数组之间的转换。在C#中,二进制数组通常用byte[]表示,...

    c# 二进制序列化 源码实例

    在C#编程中,二进制序列化是一个重要的概念,它允许我们将对象的状态转换为字节流,以便存储或在网络上传输。这个过程是通过.NET框架提供的System.Runtime.Serialization命名空间中的类来实现的。本实例将深入探讨...

    序列化和反序列化的封装类

    序列化是将一个对象的状态转换为可以存储或传输的形式,通常是XML、JSON或二进制格式。这样做的好处在于,我们可以保存对象的状态并在稍后恢复,或者将对象发送到远程服务器。在C#中,我们可以使用ISerializable接口...

    《C#序列化和反序列化之一-二进制序列化》源代码

    本资源聚焦于C#中的二进制序列化,这是一种效率高、数据紧凑的序列化方式。下面将详细阐述二进制序列化的概念、使用方法以及它在实际开发中的应用。 二进制序列化是.NET框架提供的一种机制,它可以将对象转换为原始...

    序列化和反序列化dll文件和proto

    序列化DLL文件通常涉及将内存中的函数、变量和类结构转换为二进制流或XML等文本格式,以便在磁盘上保存或通过网络发送。反序列化则是将这个流恢复为原来的函数和数据结构,使其能够在应用程序中正常工作。 接下来,...

    protobuf序列化和反序列化技术

    相比于XML或JSON等文本格式,protobuf的序列化结果更小,解析速度更快,因为它是二进制编码。此外,protobuf提供了强大的类型定义,支持复杂的数据结构,包括消息嵌套、数组和枚举类型,使得数据结构更加清晰和易于...

    java序列化(Serializable)的作用和反序列化.doc

    #### 二、序列化的应用场景 序列化在多种场景下都非常有用: 1. **对象持久化**:当你希望将内存中的对象状态保存到文件或数据库中时,序列化是一种非常有效的方式。例如,在游戏开发中,可以通过序列化保存玩家的...

    序列化和反序列化(文本加密成二进制文件)

    序列化是指将一个对象的状态转换为可存储或传输的形式,通常是二进制流;反序列化则相反,是将这个二进制流恢复为原来的对象。在本案例中,我们将关注如何将文本信息加密成二进制文件,以确保数据的安全性和不可读性...

    delphi序列化与反序列化

    在IT行业中,序列化和反序列化是两个关键的概念,特别是在对象持久化、数据传输以及存储方面。在Delphi编程环境中,这两个概念同样至关重要。本文将深入探讨Delphi中的序列化与反序列化,以及如何处理组件和结构体的...

    四种反序列化与序列化

    - **BinaryFormatter序列化**:C#的 `System.Runtime.Serialization.Formatters.Binary.BinaryFormatter` 类提供了二进制序列化功能,它将对象转换为效率高的二进制表示,适合本地存储和高效数据传输。然而,由于...

Global site tag (gtag.js) - Google Analytics