`
tubaluer
  • 浏览: 1499765 次
文章分类
社区版块
存档分类
最新评论
  • sblig: c / c++ 是不一样的都会输出 100
    j = j++

利用对象序列化深表克隆对象

 
阅读更多

在.NET上,一切都是对象。这种安排的后果之一就是在当将一个变量赋值给另一个变量的时候,会得到两个指向同一对象的变量,而不是两个不同的数据副本(除非是使用值类型而不是引用类型)。一般情况下,可以通过调用类所公开的一个特殊方法得到一个数据的副本。在.NET世界中,类应当实现ICloneable接口并公开这个接口的惟一方法Clone,让外部调用知道它能够创建类的实例的副本。框架中有多个对象可以实现这个接口,包括Array、ArrayList、BitArray、Font、Icon、Queue和Stack。

大多数的时候,实现ICloneable接口都相当的简单。所有其他类都是从System.Object 类继承来的。该类所定义的MemberwiseClone方法可以帮助复制对象,而无需手动复制对象的各个属性:

// Implements ICloneable.Clone 方法。

public object Clone()

{

// 对象属性如果是复杂类型,那么创建的仍然是其浅表副本。

//对象属性如果是复杂类型,那么复制仍然需要手动。

//只是利用MemberwiseClone复制所有的非对象值。

return this.MemberwiseClone();

}

但是,这种方法使我们使用时感到不爽,因为,只有通过更改对象定义的源代码才可以克隆一个对象,因为MemberwiseClone方法是受保护的,它只有在类的内部才可以被访问。还有,也是在多数情况下更为重要的一个方面,MemberwiseClone方法执行的是对象的浅表复制——也就是说,它创建了对象的一个副本,但是没有创建该对象所引用的其他任何对象的副本。(就是说,对象内部的数据成员如果是引用的话,还是得我们手动复制的,如果对象图非常复杂,那么我们所面对的工作是多么的繁杂,嗷嗷不爽。)

使用对象序列化来处理复杂的对象图可以同时解决前面所提到的两个问题。实际上,可以创建一个通用的方法来对任何对象进行深表克隆。

这是一个简单的提供序列化克隆对象方法:

public static object CloneObject(object obj)
{

// 创建内存流
using(System.IO.MemoryStream ms = new MemoryStream(1000))
{
object CloneObject;

// 创建序列化器(有的书称为串行器)

// 创建一个新的序列化器对象总是比较慢。
BinaryFormatter bf = new BinaryFormatter(null,
new StreamingContext(StreamingContextStates.Clone));
// 将对象序列化至流

bf.Serialize(ms, obj);

// 将流指针指向第一个字符

ms.Seek(0, SeekOrigin.Begin);

// 反序列化至另一个对象(即创建了一个原对象的深表副本)

CloneObject = bf.Deserialize(ms);

// 关闭流
ms.Close();
return CloneObject;
}
}

以下,是一个使用这个方法克隆的例子:

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;

namespace ObjectCloneBySerialize
{

class Class1
{

[STAThread]
static void Main(string[] args)
{
ArrayList Persons = new ArrayList();
Person Fangxing = new Person("Fang Xing", "Male");
Persons.Add(Fangxing);
Person Liwei = new Person("Li Wei", "Male");
Persons.Add(Liwei);

ArrayList ClonedPersons = (ArrayList)CloneObject(Persons);
Person Zhangsan = new Person("Zhang San", "Male");
ClonedPersons.Add(Zhangsan);

Console.WriteLine("===== Before Clone =====");
for(int i=0; i<Persons.Count; i++)
{
Person someone = (Person)Persons[i];
Console.WriteLine(someone.Name + " " + someone.Gender);
}

Console.WriteLine("===== After Clone =====");
for(int i=0; i<ClonedPersons.Count; i++)
{
Person someone = (Person)ClonedPersons[i];
Console.WriteLine(someone.Name + " " + someone.Gender);
}

Console.ReadLine();

}

public static object CloneObject(object obj)
{
using(System.IO.MemoryStream ms = new MemoryStream(1000))
{
object CloneObject;
BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
bf.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
CloneObject = bf.Deserialize(ms);
ms.Close();
return CloneObject;
}
}
}

[Serializable]
class Person
{
private string m_Name;
private string m_Gender;

public string Name
{
get{return m_Name;}
}

public string Gender
{
get{return m_Gender;}
}

public Person(string name, string gender)
{
m_Name = name;
m_Gender = gender;
}

}
}

分享到:
评论

相关推荐

    JavaScript浅层克隆与深度克隆示例详解

    此外,还可以利用JSON序列化和反序列化实现深度克隆,但这种方法有一些限制,例如不能处理函数和循环引用。 ```javascript function deepClone(origin, target, hash = new WeakMap()) { if (origin === null) ...

    Java实现实体类拷贝[深,很深的那种...]

    - **序列化和反序列化**:如果实体类实现了`Serializable`接口,可以利用`ObjectOutputStream`和`ObjectInputStream`进行序列化和反序列化实现深拷贝。这种方式的优点是简单,但缺点是效率较低,且所有属性都需要...

    Java深度复制功能与用法实例分析

    在这个例子中,`deepCopy`方法首先将对象序列化到字节数组,然后通过反序列化创建一个新的对象,从而实现深度复制。注意,这种方法只适用于实现了`Serializable`接口的类。对于不可序列化的类,可以考虑使用克隆方法...

    MVC总结大全

    - **实现分布式对象**:例如RMI服务,可以利用对象序列化实现远程服务调用。 - **对象的深复制**:通过序列化和反序列化可以方便地复制复杂的对象结构。 - **对象存储**:当对象需要保存到文件系统或数据库中时,...

    JavaScript数组和对象的复制

    此外,还可以利用JSON的序列化和反序列化特性,`JSON.parse(JSON.stringify(obj))`,虽然简单,但可能会丢失一些非JSON格式的属性,如构造函数。 总的来说,理解JavaScript中数组和对象的复制机制对于编写高效且无...

    详解Java中Object 类的使用.rar

    8. **序列化与反序列化**:虽然Object类不直接支持序列化,但它定义了`readObject()`和`writeObject()`方法的形参,使得子类可以实现自定义的序列化和反序列化逻辑。 通过深入学习和理解Object类及其提供的方法,...

    Java面试八股文十万字总结.docx

    - **深拷贝**:不仅复制对象本身,还递归地复制所有引用的对象。 **19. final有哪些用法** - 修饰类:表示该类不可被继承。 - 修饰方法:表示该方法不可被重写。 - 修饰变量:表示该变量的值不可改变。 **20. ...

    js代码-javascript深度克隆

    JavaScript深度克隆是一种在编程中复制对象或数组的方式,它不仅复制了基本类型的数据,还复制了引用类型的数据,确保新复制的对象与原始对象在内存中是完全独立的。在JavaScript中,浅克隆和深克隆是两个重要的概念...

    java面试笔记整理,包含java,redis,kafka等

    - **实现Serializable接口是Java对象序列化的前提条件。** - **允许对象被序列化和反序列化。 #### 四十六、显式指定serialVersionUID的原因 - **保证序列化兼容性:** 如果类的结构发生变化,serialVersionUID保持...

    Java经典编程源码基础例程300.zip

    实例057 序列化与对象克隆 84 实例058 深克隆效率的比较 87 第7章 面向对象进阶 89 实例059 经理与员工的差异 90 实例060 重写父类中的方法 92 实例061 计算几何图形的面积 93 实例062 简单的汽车销售商场 95 实例...

    SimpleJava.pdf

    - **与构造函数区别**:构造函数用于创建对象并初始化对象状态,而实例初始化块用于补充初始化。 #### 16. 为什么字段不能被重写? - **字段不可重写**:Java中字段不存在重写机制。 - **原因分析**:重写适用于...

    ActionScript3.0开发人员指南

    - **定义自定义JSON行为**:解释如何为自定义对象定义JSON序列化和反序列化规则,使其能够被正确转换。 #### 第8章 处理事件 事件驱动是AS3编程的核心概念,了解事件处理对于构建响应式用户界面至关重要。 - **...

    JAVA 面试题总览(书签完整版)

    - **深拷贝**:不仅复制对象本身,还复制其引用的对象,新旧对象完全独立。 #### 22. 数组与链表的数据结构描述及其时间复杂度 - **数组**:连续内存空间,随机访问时间复杂度O(1),插入删除操作时间复杂度O(n)。 -...

    远光软件股份有限公司 最新复试题

    - 通过序列化和反序列化操作创建对象。 #### JavaScript创建对象的方法 - 直接创建对象。 - 使用构造函数或类创建对象。 #### jQuery的选择器 - 元素选择器:选取页面中的HTML元素。 - 层叠选择器:根据层级关系...

    (完整版)2019最新Java面试题,常见面试题及答案汇总 (2).docx

    63. **深拷贝与浅拷贝**:深拷贝复制对象及其引用的对象,浅拷贝仅复制对象本身。 **Java Web** 64-67. **JSP与Servlet**:JSP是视图技术,方便页面编写;Servlet是控制逻辑,处理请求和响应。JSP内置对象有...

    Java反射机制(Reflection)浅析

    - **序列化与反序列化**:在处理对象序列化和反序列化时,反射可以用来动态地读取和设置对象状态。 - **元数据处理**:如ORM框架(如Hibernate)通过反射解析数据库表结构与Java类之间的映射关系。 - **动态代理**:...

    C++MFC教程

    |------ 3.5 利用序列化进行文件读写 |------ 3.6 MFC中所提供的各种视类介绍 +-- 第四章 窗口控件 |------ 4.1 Button |------ 4.2 Static Box |------ 4.3 Edit Box |------ 4.4 Scroll Bar |------ 4.5 List Box/...

    Java基础系列面试题(88个).pdf

    63. 浅拷贝复制对象的引用,深拷贝复制对象及其引用的对象。 64. JSP是动态网页技术,Servlet是Java Web服务端组件。JSP侧重视图,Servlet侧重逻辑。 65. JSP内置对象有request、response、session、application、...

    object:오브젝트

    Java的序列化机制允许将对象转换为字节流,以便保存到磁盘或在网络上传输。`Object`类包含`writeObject()`和`readObject()`方法的声明,但它们是抽象的,需要在子类中实现。 9. **等待/通知机制** `Object`类还...

    后端开发基础知识整理JAVA、JVM、操作系统、网络、设计模式、mysql、redis、多线程、spring、springboo

    - **序列化**:将对象的状态转化为字节流。 - **复制**:浅拷贝与深拷贝。 - **Java9的改进**:模块系统、JShell等新特性。 #### 2. JVM - **JVM的主要组成部分及其作用**:类加载器子系统、运行时数据区、执行...

Global site tag (gtag.js) - Google Analytics