13.11 深度拷贝一个ArrayCollection集合
13.11.1 问题
需要拷贝一个索引数组里的所有项或者从一个对象创建一个新对象。
13.11.2解决
使用mx.utils.ObjectUtil.copy方法
13.11.3讨论
正如演示那样,copy一个对象仅仅是为新对象创建了一个指针。意味着对第一个对象值的任何改变都会反映到第二个对象上。
var objOne:Object =
{name:"foo", data:{first:"1", second:"2"}};
var objTwo = objOne;
objOne.data.first = "4";
trace(objTwo.data.first);//traces 4

相反如果我们想要copy一个对象的全部到另一个对象中,使用mx.utils.ObjectUtil类的copy方法。该方法接受一个对象做为参数而返回一个在内存的新位置的此对象的深度拷贝。
这就意味着该对象的任何属性被copy而不再是引用原始对象相同位置的属性。如下使用此方法:
var objTwo = mx.utils.ObjectUtil.copy(objOne);
此copy方法工作机制是通过原对象创建一个ByteArray,然后再把ByteArray写入一个新对象,如下所示:
        var ba:ByteArray = new ByteArray();
        ba.writeObject(objToCopy);
        ba.position = 0;
        var objToCopyInto:Object = ba.readObject();
        return objToCopyInto;

这样原来的例子就可以如期的执行:
var objOne:Object = {name:"foo", data:{first:"1", second:"2"}};
var objTwo = objOne;
var objThree = mx.utils.ObjectUtil.copy(objOne);
objOne.data.first = "4";
trace(objTwo.data.first);//traces 4
trace(objThree.data.first);//traces 1, which is the original value
为了copy一个特定类型的对象为一个新对象存在一定难度。下面的代码会抛出一个错误:
var newFoo:Foo = ObjectUtil.copy(oldFoo) as Foo;
Flash Player并不知道如何把ByteArray转换为指定的类型。通过ByteArray,对象被序列化为AMF 二进制数据,这种方式和Flash Remoting中的一致。
为了反序列化此数据对象,该类型必须通过flash.net.registerClassAlias方法向Flash Player注册。此方法注册该类,以便该类的实例对象都可以从二进制反序列化回原对象。
registerClassAlias 需要2个参数:
public function registerClassAlias(aliasName:String, classObject:Class):void
第一个参数是此类的全类名,第二个参数是类型为Class的一个对象。全类名就是类似如下的mx.containers.Canvas or com.oreilly.cookbook.Foo.
在这里的例子中,拷贝对象时既不知道全类名也不知道该类的一个引用。幸运的是,flash.utils.getQualifiedClass会返回参数传入的对象的全类名,而flash.utils.getDefinitionByName
返回传入的对象的类引用。通过使用这2个方法,你可以注册任何对象的类:
private function copyOverObject(objToCopy:Object, registerAlias:Boolean = false):Object
{
                    if(registerAlias) {
                    var className:String = flash.utils.getQualifiedClassName(objToCopy);
                    flash.net.registerClassAlias(className,
(flash.utils.getDefinitionByName(className) as Class));
                    }
        return mx.utils.ObjectUtil.copy(objToCopy);
}
现在一个强类型对象的ArrayCollection就可以通过把集合中的每个对象传给copyOverObject方法正确的拷贝啦:
private function copyOverArray(arr:Array):Array {

        var newArray:Array = new Array();
        for(var i:int; i        newArray.push(copyOverObject(arr[i], true));
        }
        return newArray;
}
var ac:ArrayCollection = new ArrayCollection([{name:'Joseph', id:21}, foo,    
{name:'Josef', id:81}, {name:'Jose', id:214}]);
var newAC:ArrayCollection = new ArrayCollection(copyOverArray(ac.source));
值得注意的是,如果仅仅是通过mx.utils.ObjectUtil.copy来拷贝这2个ArrayCollection,那么原始ArrayCollection中的所有数据也会存在于新拷贝的ArrayCollection中。但是关于每个对象的类信息将不存在,任何企图
把该集合中一个对象强制转化为某一指定类型都将导致一个错误或空值。
 
 
 
译者注:
1.实验代码1


  
    Application{fontSize:12px;}
  

  
    import mx.controls.Alert;
    
    public function alertObj():void
    {
      var objOne:Object ={name:"张三", data:{first:"张", second:"三"}};
      var objTwo:Object = objOne;
      objOne.data.first = "李";//对原始对象的修改,也会在新对象反应出来
      Alert.show(objTwo.data.first);//输出 李    
    }    
  

 
 
2。实验代码2--深拷贝



  
    Application{fontSize:12px;}
  

  
    import mx.controls.Alert;
    import mx.utils.ObjectUtil;
    
    public function alertObj():void
    {
      var objOne:Object ={name:"张三", data:{first:"张", second:"三"}};
      var objTwo:Object =ObjectUtil.copy(objOne);//关键代码
      objOne.data.first = "李";//对原始对象的修改,不会影响第二个
      Alert.show("objOne="+objOne.data.first+"\nobjTwo="+objTwo.data.first);//
    }    
  

 
 
3.对ArrayCollection深度拷贝
 



  
    Application{fontSize:12px;}
  

  
        import mx.controls.Alert;
    import mx.utils.ObjectUtil;
    import mx.collections.ArrayCollection;
    
    public function alertObj():void
    {
      var zl:Object={name:"赵六",age:29};
      var ac:ArrayCollection = new ArrayCollection([
                    {name:'张三', age:20},
                    zl,    
                    {name:'李四', age:31},    
                    {name:'王五', age:27}
                    ]);
      var newAC:ArrayCollection = new ArrayCollection(copyOverArray(ac.source));
        
      //可以如下验证下
      //ac[2].name = "改变";
      //Alert.show(newAC[2].name);
    }    
    
    //对一个对象数组深度拷贝
    private function copyOverArray(arr:Array):Array {
      var newArray:Array = new Array();
      for(var i:int;i        newArray.push(copyOverObject(arr[i], false));//深度拷贝每个元素
      }
      return newArray;
    }    
    
    //对对象深度拷贝
    private function copyOverObject(objToCopy:Object, registerAlias:Boolean = false):Object
    {
      if(registerAlias) {
        var className:String = flash.utils.getQualifiedClassName(objToCopy);
        flash.net.registerClassAlias(className,(flash.utils.getDefinitionByName(className) as Class));
      }
      return mx.utils.ObjectUtil.copy(objToCopy);
    }    
    ]]>