`

对象序列化

 
阅读更多

当你创建对象时,只要你需要,它就会一直存在,但是在程序终止时,无论如何它都不会继续存在。如果对象能

够在程序不运行的情况下仍然存在并保存其信息,那将非常有用。这样,在下一次运行程序时,该对象将被重建

并且拥有的信息与在程序上次运行时它所拥有的信息相同。当然,可以通过将对象信息写入文件或是数据库来达

到相同的效果,但是在使万物都成为对象的精神中,如果能够将一个对象声明为是持久性的,并为我们处理掉所

有细节,那将会显得非常方便。

java的对象序列化将那些实现了Serializable接口的对象转换成为一个字节学列,并能够在以后将这个字节序列

完全恢复为原来的样子。这一过程甚至可以通过网络进行,可以在windows上创建对象并将其序列化,然后通过网

络传递给unix机子,然后在那里重新组装该对象。


对象的序列化处理非常简单,只需对象实现了Serializable接口即可(该接口仅是一个标记,没有方法)。在

Java1.1中,许多标准库类都发生了改变,以便能够序列化——其中包括用于基本数据类型的全部封装器、所有集

合类以及其他许多东西。甚至Class对象也可以序列化

为序列化一个对象,首先要创建某些OutputStream对象,然后将其封装到ObjectOutputStream对象内。此时,只

需调用 writeObject()即可完成对象的序列化,并将其发送给OutputStream。相反的过程是将一个InputStream封

装到 ObjectInputStream内,然后调用readObject()。和往常一样,我们最后获得的是指向一个上溯造型Object

的句柄,所以必须下溯造型,以便能够直接设置。

InputStream在read的时候,都是即时读取的,执行完马上就执行IO操作并返回数据。
而OutputStream为了提高效率都不是即时输出的,write会把数据先写到缓存里面,积累够了再一次性做IO输出,

所以你虽然write了,但数据还没传出去,flush方法就是强制对buffer里面的内容做IO输出。

java的io流相当于一个数据流通的管道,这里面存在一个默认的数据缓冲区,大小是8k。当我们在进行io操作的

时候,数据会经过这个缓冲区,然后保存到硬盘文件或其它存储设备文件中。如果保存过程中的数据少于8k之后,

那么这时,它就有可能把少于8k的这部分数据缓存在缓冲区中,而不写进存储设备里面,因此,我们调用当前io

流的flush()方法,清空当前缓冲区,即把数据完整的存储到文件中。


对象序列化特别“聪明”的一个地方是它不仅保存了对象的“全景图”,而且能追踪对象内包含的所有句柄并保

存那些对象;接着又能对每个对象内包含的句柄进行追踪;以此类推。我们有时将这种情况称为“对象网”,单

个对象可与之建立连接。而且它还包含了对象的句柄数组以及成员对象。若必须自行操纵一套对象序列化机制,

那么在代码里追踪所有这些链接时可能会显得非常麻烦。在另一方面,由于Java对象的序列化似乎找不出什么缺

点,所以请尽量不要自己动手,让它用优化的算法自动维护整个对象网。下面这个例子对序列化机制进行了测试

。它建立了许多链接对象的一个“Worm”(蠕虫),每个对象都与Worm中的下一段链接,同时又与属于不同类

(Data)的对象句柄数组链接:


import java.io.*;
import java.util.*;

class Data implements Serializable {
    private int n;

    public Data(int n) {
        this.n = n;
    }

    public String toString() {
        return Integer.toString(n);
    }
}

public class Worm implements Serializable {
    private static Random rand = new Random(47);
    private Data[] d = { new Data(rand.nextInt(10)),
            new Data(rand.nextInt(10)), new Data(rand.nextInt(10)) };
    private Worm next;
    private char c;

    // Value of i == number of segments
    public Worm(int i, char x) {
        System.out.println("Worm constructor: " + i);
        c = x;
        if (--i > 0)
            next = new Worm(i, (char) (x + 1));
    }

    public Worm() {
        System.out.println("Default constructor");
    }

    public String toString() {
        StringBuilder result = new StringBuilder(":");
        result.append(c);
        result.append("(");
        for (Data dat : d)
            result.append(dat);
        result.append(")");
        if (next != null)
            result.append(next);
        return result.toString();
    }

    public static void main(String[] args) throws ClassNotFoundException,
            IOException {
        Worm w = new Worm(6, 'a');
        System.out.println("w = " + w);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
                "worm.out"));
        out.writeObject("Worm storage\n");
        out.writeObject(w);
        out.close(); // Also flushes output
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(
                "worm.out"));
        String s = (String) in.readObject();
        Worm w2 = (Worm) in.readObject();
        System.out.println(s + "w2 = " + w2);
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream out2 = new ObjectOutputStream(bout);
        out2.writeObject("Worm storage\n");
        out2.writeObject(w);
        out2.flush();
        ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(
                bout.toByteArray()));
        s = (String) in2.readObject();
        Worm w3 = (Worm) in2.readObject();
        System.out.println(s + "w3 = " + w3);
    }
}
    更有趣的是,Worm内的Data对象数组是用随机数字初始化的(这样便不用怀疑编译器保留了某种原始信息)

。每个Worm段都用一个Char标记。这个 Char是在重复生成链接的Worm列表时自动产生的。创建一个Worm时,需告

诉构建器希望它有多长。为产生下一个句柄(next),它总是用减去1的长度来调用Worm构建器。最后一个next句

柄则保持为null(空),表示已抵达Worm的尾部。
    上面的所有操作都是为了加深事情的复杂程度,加大对象序列化的难度。然而,真正的序列化过程却是非常

简单的。一旦从另外某个流里创建了 ObjectOutputStream,writeObject()就会序列化对象。注意也可以为一个

String调用writeObject()。亦可使用与DataOutputStream相同的方法写入所有基本数据类型(它们有相同的接口

)。
    有两个单独的try块看起来是类似的。第一个读写的是文件,而另一个读写的是一个ByteArray(字节数组)

。可利用对任何DataInputStream或者DataOutputStream的序列化来读写特定的对象;正如在关于连网的那一章会

讲到的那样,这些对象甚至包括网络。

    可以看出,装配回原状的对象确实包含了原来那个对象里包含的所有链接。注意在对一个Serializable(可

序列化)对象进行重新装配的过程中,不会调用任何构建器(甚至默认构建器)。整个对象都是通过从

InputStream中取得数据恢复的。











该程序能打开文件,并成功读取mystery对象中的内容。然而,一旦尝试查找与对象有关的任何资料——这要求

Alien的Class对象——Java虚拟机(JVM)便找不到Alien.class(除非它正好在类路径内,而本例理应相反)。

这样就会得到一个名叫 ClassNotFoundException的违例(同样地,若非能够校验Alien存在的证据,否则它等于

消失)。
恢复了一个序列化的对象后,如果想对其做更多的事情,必须保证JVM能在本地类路径或者因特网的其他什么地方

找到相关的.class文件。
例如:

public class ThawAlien {
    public static void main(String[] args) throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(
                new File("..", "X.file")));
        Object mystery = in.readObject();
        System.out.println(mystery.getClass());
    }
}
正如大家看到的那样,默认的序列化机制并不难操纵。然而,假若有特殊要求又该怎么办呢?我们可能有特殊的

安全问题,不希望对象的某一部分序列化;或者某一个子对象完全不必序列化,因为对象恢复以后,那一部分需

要重新创建。
此时,通过实现Externalizable接口,用它代替Serializable接口,便可控制序列化的具体过程。这个

Externalizable接口扩展了Serializable,并增添了两个方法:writeExternal()和readExternal()。在序列化和

重新装配的过程中,会自动调用这两个方法,以便我们执行一些特殊操作。
下面这个例子展示了Externalizable接口方法的简单应用。注意Blip1和Blip2几乎完全一致,除了极微小的差别

(自己研究一下代码,看看是否能发现):

import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

class Blip1 implements Externalizable {
    public Blip1() {
        System.out.println("Blip1 Constructor");
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("Blip1.writeExternal");
    }

    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        System.out.println("Blip1.readExternal");
    }
}

class Blip2 implements Externalizable {
    Blip2() {
        System.out.println("Blip2 Constructor");
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("Blip2.writeExternal");
    }

    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        System.out.println("Blip2.readExternal");
    }
}

public class Blips {
    public static void main(String[] args) throws IOException,
            ClassNotFoundException {
        System.out.println("Constructing objects:");
        Blip1 b1 = new Blip1();
        Blip2 b2 = new Blip2();
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
                "Blips.out"));
        System.out.println("Saving objects:");
        o.writeObject(b1);
        o.writeObject(b2);
        o.close();
        // Now get them back:
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(
                "Blips.out"));
        System.out.println("Recovering b1:");
        b1 = (Blip1) in.readObject();
        // OOPS! Throws an exception:
        // ! System.out.println("Recovering b2:");
        // ! b2 = (Blip2)in.readObject();
    }
}

未恢复Blip2对象的原因是那样做会导致一个违例。你找出了Blip1和Blip2之间的区别吗?Blip1的构建器是“公

共的” (public),Blip2的构建器则不然,这样便会在恢复时造成违例。试试将Blip2的构建器属性变成

“public”,然后删除//!注释标记,看看是否能得到正确的结果。
恢复b1后,会调用Blip1默认构建器。这与恢复一个Serializable(可序列化)对象不同。在后者的情况下,对象

完全以它保存下来的二进制位为基础恢复,不存在构建器调用。而对一个Externalizable对象,所有普通的默认

构建行为都会发生(包括在字段定义时的初始化),而且会调用readExternal()。必须注意这一事实——特别注

意所有默认的构建行为都会进行——否则很难在自己的 Externalizable对象中产生正确的行为。
下面这个例子揭示了保存和恢复一个Externalizable对象必须做的全部事情:

 

 

 
















import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class Blip3 implements Externalizable {
    private int i;
    private String s; // No initialization

    public Blip3() {
        System.out.println("Blip3 Constructor");
        // s, i not initialized
    }

    public Blip3(String x, int a) {
        System.out.println("Blip3(String x, int a)");
        s = x;
        i = a;
        // s & i initialized only in non-default constructor.
    }

    public String toString() {
        return s + i;
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("Blip3.writeExternal");
        // You must do this:
        out.writeObject(s);
        out.writeInt(i);
    }

    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        System.out.println("Blip3.readExternal");
        // You must do this:
        s = (String) in.readObject();
        i = in.readInt();
    }

    public static void main(String[] args) throws IOException,
            ClassNotFoundException {
        System.out.println("Constructing objects:");
        Blip3 b3 = new Blip3("A String ", 47);
        System.out.println(b3);
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
                "Blip3.out"));
        System.out.println("Saving object:");
        o.writeObject(b3);
        o.close();
        // Now get it back:
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(
                "Blip3.out"));
        System.out.println("Recovering b3:");
        b3 = (Blip3) in.readObject();
        System.out.println(b3);
    }
}
其中,字段s和i只在第二个构建器中初始化,不关默认构建器的事。这意味着假如不在readExternal中初始化s和

i,它们就会成为null(因为在对象创建的第一步中已将对象的存储空间清除为1)。若注释掉跟随于

“Youmustdothis”后面的两行代码,并运行程序,就会发现当对象恢复以后,s是null,而i是零。
若从一个Externalizable对象继承,通常需要调用writeExternal()和readExternal()的基础类版本,以便正确地

保存和恢复基础类组件。
所以为了让一切正常运作起来,千万不可仅在writeExternal()方法执行期间写入对象的重要数据(没有默认的行

为可用来为一个 Externalizable对象写入所有成员对象)的,而是必须在readExternal()方法中也恢复那些数据

。初次操作时可能会有些不习惯,因为Externalizable对象的默认构建行为使其看起来似乎正在进行某种存储与

恢复操作。但实情并非如此。




1.transient(临时)关键字
控制序列化过程时,可能有一个特定的子对象不愿让Java的序列化机制自动保存与恢复。一般地,若那个子对象

包含了不想序列化的敏感信息(如密码),就会面临这种情况。即使那种信息在对象中具有“private”(私有)

属性,但一旦经序列化处理,人们就可以通过读取一个文件,或者拦截网络传输得到它。

为防止对象的敏感部分被序列化,一个办法是将自己的类实现为Externalizable,就象前面展示的那样。这样一

来,没有任何东西可以自动序列化,只能在writeExternal()明确序列化那些需要的部分。
然而,若操作的是一个Serializable对象,所有序列化操作都会自动进行。为解决这个问题,可以用transient(

临时)逐个字段地关闭序列化,它的意思是“不要麻烦你(指自动机制)保存或恢复它了——我会自己处理的”


例如,假设一个Login对象包含了与一个特定的登录会话有关的信息。校验登录的合法性时,一般都想将数据保存

下来,但不包括密码。为做到这一点,最简单的办法是实现Serializable,并将password字段设为transie
nt。下面是具体的代码:
public class Logon implements Serializable {
    private Date date = new Date();
    private String username;
    private transient String password;

    public Logon(String name, String pwd) {
        username = name;
        password = pwd;
    }

    public String toString() {
        return "logon info: \n   username: " + username + "\n   date: " + date
                + "\n   password: " + password;
    }

    public static void main(String[] args) throws Exception {
        Logon a = new Logon("Hulk", "myLittlePony");
        System.out.println("logon a = " + a);
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
                "Logon.out"));
        o.writeObject(a);
        o.close();
        TimeUnit.SECONDS.sleep(1); // Delay
        // Now get them back:
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(
                "Logon.out"));
        System.out.println("Recovering object at " + new Date());
        a = (Logon) in.readObject();
        System.out.println("logon a = " + a);
    }
}


可以看到,其中的date和username字段保持原始状态(未设成transient),所以会自动序列化。然而,password

被设为transient,所以不会自动保存到磁盘;另外,自动序列化机制也不会作恢复它的尝试。
由于Externalizable对象默认时不保存它的任何字段,所以transient关键字只能伴随Serializable使用。


Externalizable的替代方法
若不是特别在意要实现Externalizable接口,还有另一种方法可供选用。我们可以实现 Serializable接口,并添

加(注意是“添加”,而非“覆盖”或者“实现”)名为writeObject()和readObject()的方法。一旦对象被序列

化或者重新装配,就会分别调用那两个方法。也就是说,只要提供了这两个方法,就会优先使用它们,而不考虑

默认的序列化机制。
这些方法必须含有下列准确的签名:


pirvate void writeObject(ObjectOutputStream stream)throws IOException;

pirvate void readObject(ObjectInputStream stream)throws IOException,ClassNotFoundException;

从设计的角度出发,情况变得有些扑朔迷离。首先,大家可能认为这些方法不属于基础类或者Serializable接口

的一部分,它们应该在自己的接口中得到定义。但请注意它们被定义成“private”,这意味着它们只能由这个类

的其他成员调用。然而,我们实际并不从这个类的其他成员中调用它们,而是由 ObjectOutputStream和

ObjectInputStream的writeObject()及readObject()方法来调用我们对象的writeObject()和readObject()方法(

注意我在这里用了很大的抑制力来避免使用相同的方法名——因为怕混淆)。大家可能奇怪 ObjectOutputStream

和ObjectInputStream如何有权访问我们的类的private方法——只能认为这是序列化机制玩的一个把戏。
在任何情况下,接口中的定义的任何东西都会自动具有public属性,所以假若writeObject()和readObject()必须

为private,那么它们不能成为接口(interface)的一部分。但由于我们准确地加上了签名,所以最终的效果实

际与实现一个接口是相同的。
看起来似乎我们调用ObjectOutputStream.writeObject()的时候,我们传递给它的Serializable对象似乎会被检

查是否实现了自己的writeObject()。若答案是肯定的是,便会跳过常规的序列化过程,并调用writeObject()。

readObject() 也会遇到同样的情况。
还存在另一个问题。在我们的writeObject()内部,可以调用defaultWriteObject(),从而决定采取默认的

writeObject()行动。类似地,在readObject()内部,可以调用defaultReadObject()。下面这个简单的例子演示

了如何对一个Serializable对象的存储与恢复进行控制:
public class SerialCtl implements Serializable {
  private String a;
  private transient String b;
  public SerialCtl(String aa, String bb) {
    a = "Not Transient: " + aa;
    b = "Transient: " + bb;
  }
  public String toString() { return a + "\n" + b; }
  private void writeObject(ObjectOutputStream stream)
  throws IOException {
    stream.defaultWriteObject();
    stream.writeObject(b);
  }
  private void readObject(ObjectInputStream stream)
  throws IOException, ClassNotFoundException {
    stream.defaultReadObject();
    b = (String)stream.readObject();
  }
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    SerialCtl sc = new SerialCtl("Test1", "Test2");
    System.out.println("Before:\n" + sc);
    ByteArrayOutputStream buf= new ByteArrayOutputStream();
    ObjectOutputStream o = new ObjectOutputStream(buf);
    o.writeObject(sc);
    // Now get it back:
    ObjectInputStream in = new ObjectInputStream(
      new ByteArrayInputStream(buf.toByteArray()));
    SerialCtl sc2 = (SerialCtl)in.readObject();
    System.out.println("After:\n" + sc2);
  }
}
在这个例子中,一个String保持原始状态,其他设为transient(临时),以便证明非临时字段会被

defaultWriteObject()方法自动保存,而transient字段必须在程序中明确保存和恢复。字段是在构建器内部初始

化的,而不是在定义的时候,这证明了它们不会在重新装配的时候被某些自动化机制初始化。

若准备通过默认机制写入对象的非transient部分,那么必须调用defaultWriteObject(),令其作为writeObject

()中的第一个操作;并调用defaultReadObject(),令其作为readObject()的第一个操作。这些都是不常见的调用

方法。举个例子来说,当我们为一个ObjectOutputStream调用defaultWriteObject()的时候,而且没有为其传递

参数,就需要采取这种操作,使其知道对象的句柄以及如何写入所有非transient的部分。这种做法非常不便。
transient对象的存储与恢复采用了我们更熟悉的代码。现在考虑一下会发生一些什么事情。在main()中会创建一

个SerialCtl对象,随后会序列化到一个ObjectOutputStream里(注意这种情况下使用的是一个缓冲区,而非文件

——与ObjectOutputStream完全一致)。正式的序列化操作是在下面这行代码里发生的:
o.writeObject(sc);
其中,writeObject()方法必须核查sc,判断它是否有自己的writeObject()方法(不是检查它的接口——它根本

就没有,也不是检查类的类型,而是利用反射方法实际搜索方法)。若答案是肯定的,就使用那个方法。类似的

情况也会在readObject()上发生。或许这是解决问题唯一实际的方法,但确实显得有些古怪。

分享到:
评论

相关推荐

    Java对象序列化和反序列化工具Xson.zip

    Xson是一个Java对象序列化和反序列化程序。支持Java对象到字节数组的序列化,和从字节数组到Java对象的反序列化。 Maven:  <groupId>com.github.xsonorg</groupId>  <artifactId>xson-core  <version>1.0.1 ...

    Java对象序列化标准最新版

    ### Java对象序列化标准知识点详解 #### 一、系统架构概览 **1.1 概览** Java 对象序列化是一种将Java对象的状态转换成字节流的过程,以便于在网络上传输或存储到磁盘上。Java序列化标准定义了一套规则来描述如何...

    C#对象序列化与反序列化

    ### C#对象序列化与反序列化 #### 1. 对象序列化的介绍 ##### (1).NET支持对象序列化的几种方式 .NET框架提供了多种序列化机制,它们各自有不同的应用场景和特点。 - **二进制序列化**: - **定义**:二进制...

    关于 Java 对象序列化您不知道的 5 件事

    Java对象序列化是Java平台的一项重要特性,它允许将对象的状态转换为字节流,以便存储、传输或恢复。在本文中,我们将深入探讨关于Java对象序列化你可能不知道的五件事情,这些知识点对于理解和优化你的Java应用程序...

    java 对象序列化

    Java对象序列化是一种将Java对象转换为字节流的过程,以便可以存储在磁盘上、在网络上传输或在任何其他需要持久化数据的场景中使用。这个过程涉及到两个主要概念:序列化(Marshalling)和反序列化(Unmarshalling)...

    java对象序列化 传输 保存

    Java对象序列化是一种将Java对象转换为字节流的过程,以便可以存储这些对象或通过网络进行传输。这个过程是Java平台的核心特性,它允许开发者将复杂的对象结构持久化或者在网络间进行安全通信。序列化不仅可以用于...

    JAVA对象序列化保存为XML文件的工具类

    【JAVA对象序列化保存为XML文件的工具类】 在Java编程中,对象序列化是一种将对象的状态转换为字节流的过程,以便可以存储或在网络上传输。而在反序列化时,这个字节流又可以恢复为原来的对象。Java提供了一个方便...

    C#对象序列化反序列化保存与读取和对象直接保存与读取

    本主题将深入探讨如何在Windows Forms(WF)环境中,利用C#语言进行对象的直接保存与读取,以及通过对象序列化和反序列化的方式实现对象的保存与恢复。 首先,我们来理解什么是对象的直接保存与读取。在C#中,可以...

    介绍Java对象序列化使用基础

    序列化的过程就是对象写入字节流和从字节流中读取对象。...对象序列化功能非常简单、强大,在RMI、Socket、JMS、EJB都有应用。对象序列化问题在网络编程中并不是最激动人心的课题,但却相当重要,具有许多实用意义。

    对象序列化和反序列化流.xmind

    对象序列化和反序列化流

    java对象序列化.ppt

    Java对象序列化是一种将对象转换为字节流的过程,以便可以将其存储在磁盘上,或者在网络中进行传输。这是Java平台提供的一种功能,允许程序员将任何Java对象持久化,即将其状态保存到磁盘,或者在网络中进行传输。...

    VS、VC++实现对象序列化保存到sqlite表blob类型字段中,包含blob字段的读取和保存,

    在IT领域,对象序列化是一项重要的技术,它允许将复杂的数据结构转化为字节流,以便于存储或传输。本文将详细讲解如何在VS(Visual Studio)和VC++环境中实现对象序列化,并将其保存到SQLite数据库的blob(Binary ...

    java对象序列化和反序列化

    Java对象序列化与反序列化是Java编程中重要的概念,主要应用于数据持久化、网络传输以及存储等场景。本文将详细解析这两个概念及其在实际应用中的实现方式。 **一、Java对象序列化** 1. **定义**: Java对象序列化...

    android 对象序列化

    在Android开发中,对象序列化是一种重要的技术,它允许我们将对象的状态转化为可存储或可传输的数据格式,便于在不同进程间传递或者持久化保存。在标题"android 对象序列化"中,我们要讨论的是如何在Android环境中...

    java基础 对象序列化

    ### Java基础:对象序列化深度解析 #### 序列化概述与目标 对象序列化是Java编程语言中的一项核心功能,旨在将对象的状态转换为字节流,以便于存储或在网络上传输。这一过程通常涉及将对象转换为二进制格式,以便...

    论文研究-一个基于JSON的对象序列化算法.pdf

    提出了一种基于JSON的对象序列化算法,该算法通过分析JSON文法并建立对象导航图,透明地将Java对象序列化成JSON表达式,使客户端能够很好地利用JavaScript引擎来解析JSON响应,有效地解决了解析XML所造成的缺陷。

    C#对象序列化 源代码

    在.NET框架中,C#对象序列化是一种将对象的状态转换为可存储或可传输的数据格式的过程。这在很多场景下非常有用,例如保存用户会话、传输数据到远程服务器或者持久化对象到数据库。对象序列化的概念是核心的编程概念...

    对象序列化工具类

    将Java对象序列化成ISO-8859-1、Base64字节流和Xml字符串三种方式。

    XStream对象序列化

    XStream对象序列化是一种在Java应用程序中将Java对象转换为XML格式的过程,这主要通过XStream库实现。这个库提供了一种简洁的方式来处理对象到XML的转换,反之亦然,而不需要复杂的配置或对对象进行特定的修改。...

    在.NET中实现对象序列化

    对象序列化是软件开发中一个重要的概念,尤其是在分布式系统和跨平台数据交换中。在.NET框架中,对象的序列化是通过System.Xml.Serialization命名空间来实现的,这使得开发者能够将对象转换为XML格式的数据,方便...

Global site tag (gtag.js) - Google Analytics