我知道在一些分布式技术(如RPC)中,使用了术语“封送”,但不理解它与序列化有何不同。它们不是都在把对象转换成一系列的比特吗?

相关:

什么是序列化?

什么是对象编组?


当前回答

我认为主要的区别在于编组应该也涉及到代码库。换句话说,您将无法将对象编组或反编组到不同类的状态等效实例中。

序列化只是意味着您可以存储对象并重新获得等效的状态,即使它是另一个类的实例。

也就是说,它们通常是同义词。

其他回答

基础知识第一

Byte Stream - Stream is a sequence of data. Input stream - reads data from source. Output stream - writes data to destination. Java Byte Streams are used to perform input/output byte by byte (8 bits at a time). A byte stream is suitable for processing raw data like binary files. Java Character Streams are used to perform input/output 2 bytes at a time, because Characters are stored using Unicode conventions in Java with 2 bytes for each character. Character stream is useful when we process (read/write) text files.

RMI(远程方法调用)-一个API,提供了一种机制来创建java分布式应用程序。RMI允许一个对象调用另一个JVM中运行的对象的方法。


序列化和编组都被松散地用作同义词。这里有一些区别。

序列化——对象的数据成员被写入二进制形式或字节流(然后可以写入文件/内存/数据库等)。一旦将对象数据成员写入二进制形式,就不能保留任何关于数据类型的信息。

编组-对象被序列化(以二进制格式的字节流),附加数据类型+代码库,然后传递远程对象(RMI)。编组将数据类型转换为预先确定的命名约定,以便可以根据初始数据类型进行重构。

因此序列化是编组的一部分。

CodeBase是告诉Object的接收者该对象的实现可以在哪里找到的信息。任何认为自己可能会将一个对象传递给另一个之前可能没有见过它的程序的程序,都必须设置代码库,以便如果接收方在本地没有可用的代码,可以知道从哪里下载代码。在反序列化对象时,接收方将从中获取代码库并从该位置加载代码。(摘自@Nasir的回答)

序列化几乎就像对象使用的内存的一个愚蠢的内存转储,而编组存储关于自定义数据类型的信息。

在某种程度上,Serialization通过值传递的实现来执行封送,因为没有传递数据类型的信息,只是将原始形式传递到字节流。

如果流从一个操作系统到另一个操作系统,如果不同的操作系统有不同的表示相同数据的方法,序列化可能会有一些与大端序和小端序相关的问题。另一方面,编组非常适合在操作系统之间迁移,因为结果是更高级别的表示。

编组实际上使用序列化过程,但主要的区别是,它在序列化中只有数据成员和对象本身被序列化,而不是签名,但在编组对象+代码库(其实现)也将被转换为字节。

编组是使用JAXB将java对象转换为xml对象的过程,以便可以在web服务中使用它。

以下是更具体的例子:

序列化的例子:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef struct {
    char value[11];
} SerializedInt32;

SerializedInt32 SerializeInt32(int32_t x) 
{
    SerializedInt32 result;
    
    itoa(x, result.value, 10);

    return result;
}

int32_t DeserializeInt32(SerializedInt32 x) 
{
    int32_t result;
    
    result = atoi(x.value);
    
    return result;
}

int main(int argc, char **argv)
{    
    int x;   
    SerializedInt32 data;
    int32_t result;
    
    x = -268435455;
    
    data = SerializeInt32(x);
    result = DeserializeInt32(data);
    
    printf("x = %s.\n", data.value);
    
    return result;
}

在序列化中,数据以一种可以在以后存储和取消平坦化的方式被平坦化。

编组演示:

(MarshalDemoLib.cpp)

#include <iostream>
#include <string>

extern "C"
__declspec(dllexport)
void *StdCoutStdString(void *s)
{
    std::string *str = (std::string *)s;
    std::cout << *str;
}

extern "C"
__declspec(dllexport)
void *MarshalCStringToStdString(char *s)
{
    std::string *str(new std::string(s));
    
    std::cout << "string was successfully constructed.\n";
    
    return str;
}

extern "C"
__declspec(dllexport)
void DestroyStdString(void *s)
{
    std::string *str((std::string *)s);
    delete str;
    
    std::cout << "string was successfully destroyed.\n";
}

(MarshalDemo。c)

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(int argc, char **argv)
{
    void *myStdString;

    LoadLibrary("MarshalDemoLib");
    
    myStdString = ((void *(*)(char *))GetProcAddress (
        GetModuleHandleA("MarshalDemoLib"),
        "MarshalCStringToStdString"
    ))("Hello, World!\n");
    
    ((void (*)(void *))GetProcAddress (
        GetModuleHandleA("MarshalDemoLib"),
        "StdCoutStdString"
    ))(myStdString);

    ((void (*)(void *))GetProcAddress (
        GetModuleHandleA("MarshalDemoLib"),
        "DestroyStdString"
    ))(myStdString);    
}

在封送处理中,数据不一定需要被平铺,但需要转换为另一种替代表示。所有类型转换都是编组,但并不是所有编组都是类型转换。

封送处理不需要涉及动态分配,它也可以只是结构之间的转换。例如,您可能有一对,但函数期望对的第一个和第二个元素是相反的;你把一对施放/memcpy到另一对是不行的,因为FST和SND会被翻转。

#include <stdio.h>

typedef struct {
    int fst;
    int snd;
} pair1;

typedef struct {
    int snd;
    int fst;
} pair2;

void pair2_dump(pair2 p)
{
    printf("%d %d\n", p.fst, p.snd);
}

pair2 marshal_pair1_to_pair2(pair1 p)
{
    pair2 result;
    result.fst = p.fst;
    result.snd = p.snd;
    return result;
}

pair1 given = {3, 7};

int main(int argc, char **argv)
{    
    pair2_dump(marshal_pair1_to_pair2(given));
    
    return 0;
}

当您开始处理多种类型的带标签联合时,封送的概念变得尤为重要。例如,您可能会发现很难让JavaScript引擎为您打印一个“c字符串”,但您可以要求它为您打印一个包装好的c字符串。或者如果你想在Lua或Python运行时从JavaScript运行时打印字符串。它们都是字符串,但如果没有编组,通常就无法处理。

An annoyance I had recently was that JScript arrays marshal to C# as "__ComObject", and has no documented way to play with this object. I can find the address of where it is, but I really don't know anything else about it, so the only way to really figure it out is to poke at it in any way possible and hopefully find useful information about it. So it becomes easier to create a new object with a friendlier interface like Scripting.Dictionary, copy the data from the JScript array object into it, and pass that object to C# instead of JScript's default array.

(. js)

var x = new ActiveXObject('Dmitry.YetAnotherTestObject.YetAnotherTestObject');
    
x.send([1, 2, 3, 4]);

(YetAnotherTestObject.cs)

using System;
using System.Runtime.InteropServices;

namespace Dmitry.YetAnotherTestObject
{
    [Guid("C612BD9B-74E0-4176-AAB8-C53EB24C2B29"), ComVisible(true)]
    public class YetAnotherTestObject
    {
        public void send(object x)
        {
            System.Console.WriteLine(x.GetType().Name);
        }
    }
}

上面打印了"__ComObject",从c#的角度来看,这有点像一个黑盒。

Another interesting concept is that you might have the understanding how to write code, and a computer that knows how to execute instructions, so as a programmer, you are effectively marshaling the concept of what you want the computer to do from your brain to the program image. If we had good enough marshallers, we could just think of what we want to do/change, and the program would change that way without typing on the keyboard. So, if you could have a way to store all the physical changes in your brain for the few seconds where you really want to write a semicolon, you could marshal that data into a signal to print a semicolon, but that's an extreme.

编组是告诉编译器数据将如何在另一个环境/系统上表示的规则; 例如;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;

正如您可以看到的,两个不同的字符串值表示为不同的值类型。

序列化将只转换对象内容,而不是表示(将保持不变)并遵守序列化规则(导出什么或不导出什么)。例如,私有值将不会被序列化,公共值是,对象结构将保持不变。

我对编组的理解与其他答案不同。

序列化:

利用约定制作或补充对象图的有线格式版本。

编组:

利用映射文件制作或补充对象图的有线格式版本,以便可以自定义结果。该工具可以从遵循约定开始,但重要的区别在于自定义结果的能力。

合同优先开发:

编组在合同优先开发的上下文中很重要。

可以对内部对象图进行更改,同时保持外部接口的稳定。这样,所有的服务订阅者就不必为每个微不足道的更改而修改。 可以将结果映射到不同的语言。例如,从一种语言的属性名称约定('property_name')到另一种语言('propertyName')。