这段代码很无聊,因为它为一个数组添加了一个类,然后尝试将它拉出来并像操作它一样操纵它。
private function fail(event:Event):void
{
var myObj:MyClass;
var a:ArrayCollection = new ArrayCollection();
var x:MyClass;
var y:MyClass;
myObj = new MyClass;
a.addItem(myObj);
a.addItem(MyClass); // !!BAD!!
x = a[0];
y = a[1];
}
当我意外地做到这一点时,我花了很长时间才看到我做错了什么。部分是因为错误消息没有告诉我任何我能理解的内容:
TypeError: Error #1034: Type Coercion failed: cannot convert com.ibm.ITest::MyClass$ to com.ibm.ITest.MyClass.
at ITest/fail()[C:\work_simple01\ITest\src\ITest.mxml:51]
at ITest/___ITest_Button5_click()[C:\work_simple01\ITest\src\ITest.mxml:61]
所以我的问题是,为什么标记线!!坏!以上甚至允许?我希望这里有编译时错误。由于它编译,必须有一些用途,我不知道。它是什么?
答案 0 :(得分:8)
在我看来,这个问题等同于“为什么我可以将一个类用作值?”这是一个很好的问题。
在ActionScript中,您可以使用两个主要功能;你可以实例化它,你可以访问它的静态属性。 (好吧,还有其他的东西,但那些是显而易见的。)实例化一个类可能是一个类作为一个值最相关的用法; Class是它自己的factory,就像你在C ++或Java中明确表达的那样。
以下是我作为练习写的一个小型俄罗斯方块游戏的例子。我有两个课,Brick和SceneBrick。一块砖是一块游戏中的砖块,那些落下并堆积起来的砖块。 SceneBrick是一块刚刚作为游戏区框架绘制的砖块。
但是,我使用一个函数来绘制它们,而不引用函数中的任何一个类型:
function drawBricks(xs:Array, ys:Array, brickType:Class){
xs.map(function(o,i,a){
var brick = new brickType();
// etc.
});
}
我可以这样使用:
drawBricks([0,1,2,3], [4,4,4,4], Brick); // draw a long piece
drawBricks(times(0, 21), countFrom(0, 21), SceneBrick); // draw a big vertical "wall"
在ActionScript中,您可以将类作为值传递,并使用它来实例化该类。在Java或C ++这样的语言中,您必须将其用作泛型类的参数,或者使用一些常见的超类型定义工厂类才能执行此操作。
答案 1 :(得分:7)
我认为异常发生在您样本的最后一行,而不是您标记为'BAD'的错误。
您添加到数组中的是表示“MyClass”类的对象,而不是MyClass的实例。
能够在运行时检查类是一个强大的功能,是.NET和Java中反射功能的基础。这些功能通常用于支持可扩展性模式或实现序列化框架。
因此,操纵其中一个对象是有效的事情......因为它不是MyClass的实例,所以你不能将它分配给你的y变量。
答案 2 :(得分:1)
似乎在Flex中,集合不指定它们应包含的值的类型。
var a:ArrayCollection = new ArrayCollection();
因此,编译器不会检查您添加到其中的值的类型,这对我来说是合乎逻辑的。然后,只能在运行时检查从集合元素中分配变量,因为编译器没有这些信息。
对于作为对象的类(以及响应消息),构建所有类型的调试/检查/反射工具非常方便。
答案 3 :(得分:0)
后期绑定(和动态语言)的好处在于它允许您在实现方面具有更大的灵活性。缺点是该语言不能保护您免受早期绑定和强类型阻止的一些简单错误的影响。就个人而言,我会考虑使用TDD(测试驱动开发)来帮助防止这些错误蔓延到您的代码中。