Actionscript 3 AS3优化:隐式铸造vs.“;作为「;在参数和变量赋值中;什么';到底发生了什么事?

Actionscript 3 AS3优化:隐式铸造vs.“;作为「;在参数和变量赋值中;什么';到底发生了什么事?,actionscript-3,optimization,casting,Actionscript 3,Optimization,Casting,已经证明(例如中的参考文献)在AS3中使用“as”关键字比使用括号铸造快3-4倍。这是因为(投射)可以更好地描述为插值,实际上生成一个新对象,而不是真正投射旧对象。(cast)如果在“as”运算符返回null时失败,则抛出类型错误。好吧 这里有三个问题: (1) 当您将一个数字传递给一个需要(int)的函数时,或者当您将一个精灵传递给一个需要DisplayObject的函数时,会发生什么?i、 e.如果函数需要父类。如果预期的类是作为参数传递的对象的优势类,是否生成新的局部作用域对象?在调用函数

已经证明(例如中的参考文献)在AS3中使用“as”关键字比使用括号铸造快3-4倍。这是因为(投射)可以更好地描述为插值,实际上生成一个新对象,而不是真正投射旧对象。(cast)如果在“as”运算符返回null时失败,则抛出类型错误。好吧 这里有三个问题:

(1) 当您将一个数字传递给一个需要(int)的函数时,或者当您将一个精灵传递给一个需要DisplayObject的函数时,会发生什么?i、 e.如果函数需要父类。如果预期的类是作为参数传递的对象的优势类,是否生成新的局部作用域对象?在调用函数之前使用“as”强制转换参数是否明显更快

(2) 例如,在一个for-each(someNumberVector中的var i:int)或一个for-each循环中将每个精灵视为一个DisplayObject时发生了什么?是否在循环的每一步都通过慢速(不是“as”而是容易出错)方法重新播放每一个片段


(3) 函数或变量赋值期望接口实现类(或接口本身,例如IEventDispatcher)与期望父类(使用哪种方法(克隆或强制转换)来“强制转换”原始变量)有什么区别吗

传递子类型的对象(或迭代子类型列表等)时,不需要强制转换或转换——对象就是该子类型,可以直接传递。原因是,具有继承的对象的内存布局通常实现为基本对象的数据,然后是下一个继承类的数据,等等。加上一个vtable指针,以允许方法重写/接口实现:

// class Sub : Base
obj -> +----------+
       |vtable ptr| -.      vtable
       |----------|   `-> +---------+
       |Base data |       | Method1 |
       |----------|       +---------+
       |Sub data  |       | Method2 |
       +----------+       +---------+
当传递子对象时,底层指针指向内存中对象的起始点——这与内存中基本对象的起始点完全相同,因此在内部将子对象转换为基本对象时无需执行任何操作;唯一的区别是变量的使用方式(类型检查语义)。实际的对象值和对它的引用完全不需要转换(无论如何,在sane实现中)

添加强制转换只会降低速度(除非编译器足够聪明,可以删除强制转换,这是应该的,但我对AS3编译器的优化功能没有太多信心)

但是,将
Number
s转换为
int
s,反之亦然,这是完全不同的,因为这需要转换值的内部表示形式,这很慢

注意对对象的引用(变量的实际值只是该对象的句柄)和值类型(变量的实际值是值本身,而不是间接值)之间的区别。例如,
int
变量保存实际的整数变量,而
Object
类型的变量只保存对某个对象的引用。这意味着,如果您使用
Object
类型的变量(或默认情况下
Object
类型的非类型变量),并尝试在其中粘贴一个整数,这将导致所谓的“装箱”操作,该操作将取值并将其粘贴到临时对象中,以便该变量可以保留对它的引用。将其作为整数处理(或显式强制转换),会导致取消装箱值的装箱,这显然不是即时的


可以看出,将对象投射到其底部并不慢,因为没有工作要做。将基强制转换为派生类型几乎同样快(因为也不必对其中的内部指针执行任何操作),只是必须执行检查以确保对象确实是派生类型(根据执行的强制转换类型导致异常或null)。将值类型强制转换为对象类型或将值类型强制转换为对象类型不是很快,因为除了运行时类型检查外,还必须对值执行装箱/取消装箱操作。最后,将一种基本类型转换为另一种类型的速度特别慢,因为内部表示完全不同,因此转换需要付出相应的更多努力。

(1)Number->int:slow必须转换。精灵->显示对象:快速,无需工作。(2) 迭代int-vector不需要任何额外的工作(取决于vector的内部实现),除非该向量不是声明为int的向量,而是声明为其他内容的向量,其中每次迭代都需要转换。Sprite->DisplayObject再次是即时的,因为无需做任何事情。(3) 不。好的,只是澄清/扩展一下:如果我有一个动态加载的实例——我们称它为var bit:*——我知道它扩展了位图(例如,加载程序的.content),我想访问它上的位图方法,就像获取它的bitmapData一样,我知道说它要快得多(位为位图).bitmapData,而不是位图(位).bitmapData。所以我的问题是,如果我将这个变量作为参数发送到一个需要位图的函数中,会发生什么。然后进行哪种类型的铸造?如果我们100%知道arg扩展位图,为什么编译会有所不同呢?
*
不是一种类型;它扩展到编译时分配给该变量的任何类型(类型推断)。发生的情况取决于变量的类型。这是因为如果类型扩展了
Bitmap
,编译器在编译时就知道,无论实际对象是否属于子类,运行时引用的变量都将是有效的
Bitmap
(或null)。如果类型是,比如说,
对象
,那么对象不能盲目地用作
位图
,因为在运行时变量可以引用任何类型的对象,而不仅仅是
位图
。。。。。。因此,编译器必须生成代码才能进行类型转换