我以为我在AS3中找到了参考资料,但以下行为让我感到困惑:
// declarations for named individual reference later on
var myAmbientSound:Sound;
var myAmbientSoundLocation:String = "http://ambient_sound_location";
var myPeriodicSound:Sound;
var myPeriodicSoundLocation:String = "http://periodic_sound_location";
var myOccasionalSound:Sound;
var myOccasionalSoundLocation:String = "http://occasional_sound_location";
// for iterating through initialization routines
var mySoundArray:Array = [myAmbientSound, myPeriodicSound, myOccasionalSound];
var mySoundLocation:Array = [myAmbientSoundLocation, myPeriodicSoundLocation, myOccasionalSoundLocation];
// iterate through the array and initialize
for(var i:int = 0; i < mySoundArray.length; i++) {
mySoundArray[i] = new Sound();
mySoundArray[i].load(new URLRequest(mySoundLocation[i]));
}
此时,我认为mySoundArray[0]
会引用与myAmbientSound
相同的对象;但是,访问myAmbientSound
会抛出空指针异常,而mySoundArray[0]
会按预期工作并引用Sound
对象。我在这里误解了什么?
答案 0 :(得分:7)
它更像是java引用变量而不是C指针。
var myAmbientSound:Sound;
var myPeriodicSound:Sound;
var myOccasionalSound:Sound;
//these variables are not initialized and hence contain null values
现在创建一个包含这些变量的当前值(null)的数组
var mySoundArray:Array = [myAmbientSound, myPeriodicSound, myOccasionalSound];
现在,数组包含三个空值[null, null, null]
,而不是指向Sound
个对象的三个指针。
现在,当您调用mySoundArray[0] = new Sound();
时,会创建一个新的Sound
对象并将其地址分配给该数组的第一个位置 - 它不会修改myAmbientSound
变量。
答案 1 :(得分:3)
由于其他人花了很多时间提出一些非常好的解释,我会试着暗中解决你提出的问题:
此时,我认为
mySoundArray[0]
会将同一个对象引用为myAmbientSound
但是myAmbiendSound
没有引用任何内容。从你的代码:
var myAmbientSound:Sound;
上面只是创建一个Sound类型的局部变量,一个潜在的引用。用外行人的话说,一个可以指向某种东西的“手指”。所有局部变量都是引用。顺便说一下,并非所有引用都是局部变量,对象属性也是引用,Array
和Vector
元素也是如此。无论如何,上面的表达式不会创建Sound
类的对象。它只声明一个可能引用Sound
类对象的局部变量。声明后,它具有特殊值undefined
。
声明上面的变量并为其赋值是有区别的。运算符new
创建一个对象并返回对它的引用。赋值运算符=
导致左侧引用的任何内容,右侧的任何内容,粗略地放置。
使局部变量高于引用对象的一种方法是:
myAmbientSound = new Sound();
在你的情况下,就像我说的那样,myAmbientSound
变量有一个特殊的undefined
值,因为你只是声明它,而且还没有赋值。另外,正如我们从代码中看到的那样,它在代码片段的整个运行时期间都没有引用任何内容。
现在,在我解释你最终用你的行放入你的数组之前:
var mySoundArray:Array = [ myAmbientSound, ...
,你必须记住,数组元素,就像对象属性一样,也是引用 - 例如mySoundArray[0]
可以引用一个对象,可能会引用mySoundArray[1]
等等。
上面的代码行声明了一个新的局部变量,使它引用一个新的数组对象。声明和定义在一个单一的声明中。
现在,由于我们已确定您的本地变量myAmbiendSound
包含特殊的undefined
值,因此您的第一个数组元素最终会引用相同的值 - undefined
,最初< / strong>即可。在稍后的循环中,你有第一个元素(或者,如果我们要谨慎,变量i
引用的数字处的元素)引用一个新的Sound
对象。此时(以及我们观察到的整个代码段范围),由于myAmbiendSound
为undefined
,因此将两者进行比较将失败 - 它们不会引用同一个对象,它们引用的对象也不是“相等的”(如果=
在AS3中的工作方式是另一个主题) - 前者是undefined
,后者指向Sound
个对象。
此外,一个小修正:“访问”对象不会导致运行时异常。尝试访问不指向对象的引用的属性(使用点表示法语法)会导致运行时异常。这就像你写trace(null.foo)
- null
不是一个对象,当然也没有名为foo
的属性。同样适用于undefined
。
顺便说一下,null == undefined
为true
,但null === undefined
为false
。只是说。在很少发生时(当然取决于你),你必须尊重这个细节。
我希望这可以解决问题。我认为这是前面所说的所有内容的补充。
答案 2 :(得分:2)
通常,ActionScript,Java和其他语言中的引用不会被视为C / C ++中的引用。如果引用在C / C ++中起作用,那么您编写的代码将是正确的并且按预期工作。通常,您应该尝试将引用视为自动解引用指针。您的代码是C / C ++引用和现代引用之间差异的一个很好的例子。
以下是此行为的后果示例,因为它适用于垃圾收集器:
var someRef:Sound = new Sound();
someRef = null;
然后我在第一行创建的Sound对象仍然存在,并且可能继续存在。这一点很重要,因为如果在AS3中注册事件侦听器,则会为它们创建一个额外的引用,以防止它们被GC销毁。这就是为什么你应该几乎总是使用对AddEventListener的完全调用,强制它使用弱引用(不计入GC)。
此外,请记住,所有函数调用都是AS3中的ByVal。所以这段代码不起作用:
function initSound(a:Sound, b:String):void {
a = new Sound();
a.load(new URLRequest(b);
}
var myAmbientSound:Sound;
var myAmbientSoundLocation:String = "http://ambient_sound_location";
initSound(myAmbientSound, myAmbientSoundLocation);
好消息是,大多数内置垃圾收集的语言都具有相同的引用行为,因此一旦掌握了它,您就能更快地获取这些语言。
答案 3 :(得分:1)
定义变量不会创建指针。
// This line is only creating a QName, but no pointer.
// Value of "myAmbientSound" is "null".
var myAmbientSound : Sound;
// Here, you put the reference pointed by myAmbientSound into the array.
// It is null, so mySoundArray[0] will also be null.
var mySoundArray : Array = [myAmbientSound];
// Here, you assign a new pointer to the index 0 of mySoundArray.
// It is simply overwriting the "null" value, but there is no
// connection to myAmbientSound.
mySoundArray[0] = new Sound();
// myAmbientSound is still null, as it is still pointing to nothing.
trace(myAmbientSound); // null
// But index 0 of mySoundArray holds a pointer to the sound you instanciated.
trace(mySoundArray[0]); // [Object Sound]
要实现您的目标,您必须做同样的事情:
// Creating the variable and pointing it to an object instance.
var myAmbientSound : Sound = new Sound();
// Here, the pointer isn't null, so the reference can be added to the array.
var mySoundArray : Array = [myAmbientSound];
// And now, both accessors points to the same object instance.
trace(myAmbientSound); // [Object Sound]
trace(mySoundArray[0]); // [Object Sound]