关于as3实现对任何对象进行深刻复制的思考
无意中看到关于as3深度复制思考的文章,觉得不错,于是转来记录以后用到可以参考。
转载来源:http://xmchcly.iteye.com/blog/1307425,下面是转文:
通过 ByteArray 可以对数组和 Object 进行深度复制,脚本网上满天飞:
var obj:Object = new Object();
var ba:ByteArray = new ByteArray();
ba.writeObject(obj);
ba.position = 0;
var obj2:Object = ba.readObject();
我就想了,能不能用这种方法对任何对象都进行深度复制呢?
试试这样,一般来说网上说了是对数组和 Object,那么对于其它类型多半都会有问题:
var s:Sprite = new Sprite();
var ba:ByteArray = new ByteArray();
ba.writeObject(s);
ba.position = 0;
var s2:Sprite = ba.readObject();
嗯,果然抛错了:
Exception fault: TypeError: Error #1034: 强制转换类型失败:无法将 Object@128a309 转换为 flash.display.Sprite。
那我们再改一下看看
var s:Sprite = new Sprite();
var ba:ByteArray = new ByteArray();
ba.writeObject(s);
ba.position = 0;
var s2:Sprite = ba.readObject() as Sprite;
运行,等于没改,异常依旧。
好了,不买关子了,直接上个能用的,用全局函数 registerClassAlias 注册一下 Sprite 即可:
//关键就是这句
registerClassAlias("flash.display.Sprite", Sprite);
var s:Sprite = new Sprite();
s.x = 100;
var ba:ByteArray = new ByteArray();
ba.writeObject(s);
ba.position = 0;
var s2:Sprite = ba.readObject() as Sprite;
trace("复制的对象 x : ", s2.x);
s2.x = 200;
trace("源的对象 x : ", s.x, "复制的对象 x : ", s2.x);
我们看看输出了什么:
复制的对象 x : 100
源的对象 x : 100 复制的对象 x : 200
哦也,对象成功的复制出来了,等等,好像还输出了什么,待我看看先:
TypeError: Error #1034: 强制转换类型失败:无法将 Object@12883f9 转换为 flash.media.SoundTransform。
TypeError: Error #1034: 强制转换类型失败:无法将 Object@1288629 转换为 flash.geom.Transform。
我转换的是 Sprite 呀,关这个两个类型啥事?后来想了想,貌似 Sprite 里有 自己的 soundTransform 属性和继承自 DisplayObject 的 transform 属性,那好办呀,把他俩也注册一下不就行了。
可是这样还是很麻烦,毕竟我们要把深度复制的对象用到的类都注册一遍,有没有什么办法可以取出该类包括其父类 import
的所有类呢,这里我们可以用另外的一个全局函数 describeType,这个函数吧一个类或类的实例的所有详细说明都取出作为 xml
对象返回,大家可以看看这个返回的数据就知道了:
var xml:XML = describeType(new Sprite());
trace(xml);
好了我们创建一个函数把该类包括其父类 import 的类都取出来吧:
public static function getAllQualifiedClassName($object:*):Array{
if($object == null){
throw new ArgumentError("Parameter $object can not be null.");
return null;
}else{
var xml:XML = describeType($object), dictionary:Dictionary = new
Dictionary(), i:int, j:int, result:Array = new Array();
dictionary[xml.@name] = true;
for(i=0; i<xml.extendsClass.length(); i++){
dictionary[String(xml.extendsClass[i].@type)] = true;
}
for(i=0; i<xml.implementsInterface.length(); i++)
dictionary[String(xml.implementsInterface[i].@type)] = true;
for(i=0; i<xml.accessor.length(); i++)
dictionary[String(xml.accessor[i].@type)] = true;
for(i=0; i<xml.method.length(); i++){
dictionary[String(xml.method[i].@returnType)] = true;
for(j=0; j<xml.method[i].parameter.length(); j++)
dictionary[String(xml.method[i].parameter[j].@type)] = true;
}
for(var obj:* in dictionary)
if(String(obj) != "void" && String(obj) != "*")
result.push(String(obj));
return result;
}
}
考虑到会有很多地方用到就把它静态了,注意 void 和 * 需要剔除,我们取到了所有需要注册的类,接下来就是把他们一并注册了事,嘿嘿嘿:
var allClassName:Array = HObjectUtils.getAllQualifiedClassName(new Sprite());
for each(var item:String in allClassName)
registerClassAlias(item, Class(getDefinitionByName(item)));
var s:Sprite = new Sprite();
s.x = 100;
var ba:ByteArray = new ByteArray();
ba.writeObject(s);
ba.position = 0;
var s2:Sprite = ba.readObject() as Sprite;
trace("复制的对象 x : ", s2.x);
s2.x = 200;
trace("源的对象 x : ", s.x, "复制的对象 x : ", s2.x);
可是没想到一运行fp就给了我当头一棒:
Exception fault: ArgumentError: Error #1063: flash.geom::Transform() 的参数数量不匹配。应该有 1 个,当前为 0 个。
没想到 ByteArray 的 writeObject 和 readObject
对构造函数带必填参数的对象有先天性的支持缺陷,也就是说如果你要深度复制的对象或它的一个属性指向的对象的构造函数是需要参数的话,不好意思了,
writeObject 和 readObject
可没办法传参数,这个方法将会失效,但是我可不甘心,如果说不支持带参数的构造函数的话,我就试试不带参数的情况下这个方法走不走得通,至于构造函数带有
参数的深度复制可以寻找其它的路径解决。
这里我弄了个例子:
深度复制类:ObjectUtils
package {
import flash.utils.getQualifiedClassName;
import flash.utils.Dictionary;
import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import flash.net.registerClassAlias;
import flash.utils.ByteArray;
public class ObjectUtils {
public static function cloneObject($object:*):*{
if($object == null){
throw new ArgumentError("Parameter $object can not be null.");
return null;
}else{
//为了深度复制一个对象, 需要注册该对象用到的所有类
var allClassName:Array = getAllQualifiedClassName($object);
for each(var item:String in allClassName)
registerClassAlias(item, Class(getDefinitionByName(item)));
//使用 byteArray 对象进行深度复制即可
var bytes:ByteArray = new ByteArray();
bytes.writeObject($object);
bytes.position = 0;
//取出复制出的新对象,如果有带参数的构造函数而导致复制失败的就返回 null
var className:String = getQualifiedClassName($object);
var ObjectClass:Class = Class(getDefinitionByName(className));
var result:*;
try{
result = bytes.readObject() as ObjectClass;
return result;
}catch($error:ArgumentError){
trace($error.message);
}
return null;
}
}
public static function getAllQualifiedClassName($object:*):Array{
if($object == null){
throw new ArgumentError("Parameter $object can not be null.");
return null;
}else{
var xml:XML = describeType($object), dictionary:Dictionary = new
Dictionary(), i:int, j:int, result:Array = new Array();
dictionary[xml.@name] = true;
for(i=0; i<xml.extendsClass.length(); i++){
dictionary[String(xml.extendsClass[i].@type)] = true;
}
for(i=0; i<xml.implementsInterface.length(); i++)
dictionary[String(xml.implementsInterface[i].@type)] = true;
for(i=0; i<xml.accessor.length(); i++)
dictionary[String(xml.accessor[i].@type)] = true;
for(i=0; i<xml.method.length(); i++){
dictionary[String(xml.method[i].@returnType)] = true;
for(j=0; j<xml.method[i].parameter.length(); j++)
dictionary[String(xml.method[i].parameter[j].@type)] = true;
}
for(var obj:* in dictionary)
if(String(obj) != "void" && String(obj) != "*")
result.push(String(obj));
return result;
}
}
}
}
人物类:Person
package {
import flash.utils.ByteArray;
public class Person {
private var _name:Name = new Name();
private var _age:int = 1;
private var _bytes:ByteArray;
public function Person(){
}
public function set name(v:Name):void{
_name = v;
}
public function get name():Name{
return _name;
}
public function set age(v:int):void{
_age = v;
}
public function get age():int{
return _age;
}
public function set bytes(v:ByteArray):void{
_bytes = v;
}
public function get bytes():ByteArray{
return _bytes;
}
public function talk():String{
_bytes.position = 0;
var dream:String = "";
while(_bytes.position<_bytes.length)
dream += _bytes.readUTF();
return "我叫"+_name.x+_name.m+",我"+_age+"岁,我的梦想是"+dream;
}
}
}
名字类:Name
package {
public class Name {
private var _x:String = "";
private var _m:String = "";
public function Name(){
}
public function set x(v:String):void{
_x = v;
}
public function get x():String{
return _x;
}
public function set m(v:String):void{
_m = v;
}
public function get m():String{
return _m;
}
}
}
主类:Main
package {
import flash.utils.ByteArray;
import flash.events.Event;
import flash.display.Sprite;
public class Main extends Sprite {
public function Main(){
if(stage)
init();
else
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void{
var a:Person = new Person();
var aName:Name = new Name();
a.name = aName;
a.age = 20;
aName.x = "张";
aName.m = "三";
a.bytes = new ByteArray();
a.bytes.writeUTF("娶个媳妇!");
trace("源对象:", a.talk());
var b:Person = ObjectUtils.cloneObject(a) as Person;
trace("深度复制后的对象:", b.talk());
trace("复制出的对象改变值了!!!看看复制出的对象的值的改变会否影响到源对象!!!");
b.name.x = "李";
b.name.m = "四";
b.age = 22;
b.bytes.position = b.bytes.length;
b.bytes.writeUTF("再买栋房子!");
trace("源对象:", a.talk());
trace("深度复制后的对象:", b.talk());
}
}
}
我们看看输出:
源对象: 我叫张三,我20岁,我的梦想是娶个媳妇!
深度复制后的对象: 我叫张三,我20岁,我的梦想是娶个媳妇!
复制出的对象改变值了!!!看看复制出的对象的值的改变会否影响到源对象!!!
源对象: 我叫张三,我20岁,我的梦想是娶个媳妇!
深度复制后的对象: 我叫李四,我22岁,我的梦想是娶个媳妇!再买栋房子!
为了测试我特意弄了一个 Name 类又使用了 ByteArray
对象,现在看来一切运行良好,唯一的遗憾就是不能支持构造函数带参数的对象的深度复制,关键是只要需要复制的对象和构造函数带参数的对象拉上哪怕一点点关
系也要失败,这样一来该 ObjectUtils 工具类的使用面就大打折扣了。
不知道各位仙家有没有更好的方法真正实现任意对象的深度复制,还有本文如有错误也请不吝指教。
另外一种方法的思考:是否可以用 describeType 取出对象的所有属性后在 new
出一个该对象,再把源对象的值逐一复制到新的对象上,如果有属性是引用了另一个对象就在用同样的方法创建该新对象的,直到所有属性都指向新创建的对象为
止,这样我们就可以在 new 该对象时把构造函数的参数添加上去了。
另外说一下,用 ByteArray 复制对象时只复制该对象的 public 属性,如果你有一个私有属性,并且该私有属性是通过一个非 set 函数进行赋值的话,该私有属性的值则不会被复制到新的对象中。
======================================================
最近有点儿时间,帖点儿小经验给大家.有不妥之处敬请包涵.
用byteArray克隆对象,估计大家大多数都用过.应该是类似下面的实现
01.var copier:ByteArray = new ByteArray();
02. copier.writeObject(source);
03. copier.position = 0;
04. return copier.readObject();
复制代码但对于一个相当复杂的对象,要达到完全克隆,还面临着很多问题.
比如下面这几种情况:
1:属性是自定义类型
2.属性是数组,而且数组元素是自定义类型
3.属性是接口形式,但现实是某种实现
4.属性是Dictionary
等等.不知道大家是否碰到过这样的情况.
所以经过研究,对上面的方法进行了一些拓展.形成了下面这种方式进行克隆.
private static function regtype(tn:String):void {
if (tn == null || tn == "null" || tn == "int" || tn == "string" || tn ==
"Number" || tn == "String" || tn == "Boolean" || tn == "Object")return;
var type:Class;
try {
type = getClassByAlias(tn);
} catch(err:Error) {
}
if (type != null)return;
try {
type = Class(getDefinitionByName(tn));
} catch(err:Error) {
return;
}
if (type == null)return;
registerClassAlias(tn, type);
}
private static function registerClass(source:*):void {
var tn:String = getQualifiedClassName(source);
regtype(tn);
if(tn=="Array"||tn=="flash.utils::Dictionary"){
for(var ele:String in source){
registerClass(source[ele]);
}
}
var dxml:XML = describeType(source);
for each(var acc:XML in dxml.accessor) {
registerClass(source[acc.@name]);
}
for each(var acc1:XML in dxml.variable) {
registerClass(source[acc1.@name]);
}
for each(var acc2:XML in dxml.implementsInterface) {
regtype(acc2.@type);
}
regtype(dxml.extendsClass.@type);
}
public static function baseClone(source:*):* {
registerClass(source);
var copier:ByteArray = new ByteArray();
copier.writeObject(source);
copier.position = 0;
return copier.readObject();
}
其中baseClone是入口方法,其余两个做辅助工作.具体原理是:
1.用describeType方法对原始对象进行结构分析
2.把原始对象的复杂属性注册别名
3.递归进行2操作.
关于as3实现对任何对象进行深刻复制的思考的更多相关文章
- Java提高篇——对象克隆(复制)
假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...
- 转载---Java集合对象的深度复制与普通复制
原博文:http://blog.csdn.net/qq_29329775/article/details/49516247 最近在做算法作业时出现了错误,原因是没有弄清楚java集合的深度复制和浅度复 ...
- Java中对象的深复制和浅复制详解
1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...
- JavaScript对象的深浅复制
前言 从层次上来看,对象的复制可以简单地分为浅复制和深复制,顾名思义,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,对象的深复制会复制对象中层层嵌套的对象的属性. 在复制对象时,除了要复 ...
- js中对象的深度复制
// 对象的深度复制 cloneObj(oldObj) var cloneObj = function (obj) { var newObj = {}; if (obj instanceof Arra ...
- Objective-C:OC内部可变对象和不可变对象的深(复制)拷贝问题思考:
OC内部:可变对象和不可变对象的深(复制)拷贝问题思考: 不可变对象: 例如NSString对象,因为NSString对象是常量字符串,所以,不可以更改其内容,但是可以修改指向该字符串的指针指向 ...
- java对象实现深复制的方法
p2 = (Person)org.apache.commons.lang3.ObjectUtils.cloneBean(p); Person p2 = new Person(); p2 = (Pers ...
- javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())
javascript 数组和对象的浅度复制和深度复制在平常我们用 ‘=’来用一个变量引用一个数组或对象,这里是‘引用’而不是复制下面我们看一个例子引用和复制是什么概念 var arr=[1,2,3,' ...
- JavaScript 对象的深复制
对象的深复制 源对象的属性更改,不会引起复制后的对象个属性的更改 源对象的任何属性与子属性与新对象的之间没有任何引用关系 Coding: /* 对象的深复制: 1 初始化目标对象 如果没有指定目标对象 ...
随机推荐
- [HNOI 2013] 消毒 (搜索,二分图匹配)
题目大意 一个a * b * c(a * b * c <= 5000)大小的长方体中有一些点需要被覆盖,每次可以选择任意大小的长方体,覆盖其中的点,产生的代价为这个长方体长宽高中最小的那个的长度 ...
- uva 10714 Ants(贪心)
题目连接:10714 - Ants 题目大意:一根棍子上有n只蚂蚁, 这些蚂蚁开始可以任意朝着一个方向移动一直走,向左或是向右,并且移动速度是相同的,但是一旦蚂蚁碰到迎面走来的另一只蚂蚁,那么这两只蚂 ...
- ACdream 1417 Numbers
pid=1417">题目链接~~> 做题感悟:比赛的时候用的广搜,然后高高兴兴的写完果断TLE .做题的时候不管什么题都要用笔画一下,模拟几组数据,这样或许就AC了(做题经验,有 ...
- 最小公约数(欧几里得算法&&stein算法)
求最小公约数,最easy想到的是欧几里得算法,这个算法也是比較easy理解的,效率也是非常不错的. 也叫做辗转相除法. 对随意两个数a.b(a>b).d=gcd(a.b),假设b不为零.那么gc ...
- android repo库的创建及代码管理
- sql中的case when
sql语言中有没有类似C语言中的switch case的语句?? 没有,用case when 来代替就行了. 例如,下面的语句显示中文年月 select ...
- Java基础知识强化60:经典查找之二分查找
1. 二分查找 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表. 比较 ...
- Python 文件I/O (转)
Python 文件I/O 本章只讲述所有基本的的I/O函数,更多函数请参考Python标准文档. 打印到屏幕 最简单的输出方法是用print语句,你可以给它传递零个或多个用逗号隔开的表达式.此函数把你 ...
- css伪类选择器详细解析及案例使用-----伪类选择器(1)
动态伪类选择器:E:link :选择匹配的E元素,并且匹配元素被定义了超链接并未被访问过.E:visited :选择匹配的E元素,而且匹配的元素被定义了连接并已被访问过.E:active :选择匹配的 ...
- javascript 冒泡和事件源 形成的事件委托
冒泡:即使通过子级元素的事件来触发父级的事件,通过阻止冒泡可以防止冒泡发生. 事件源:首先这个东西是有兼容行问题的,当然解决也很简单. 两者结合使用,形成的事件委托有两个优势: 1.减少性能消耗: 2 ...