ActionScript 3.0 包

 

在 ActionScript 3.0 中,包是用命名空间实现的,但包和命名空间并不同义。在声明包时,可以隐式创建一个特殊类型的命名空间并保证它在编译时是已知的。显式创建的命名空间在编译时不必是已知的。

下面的示例使用 package 指令来创建一个包含单个类的简单包:

package samples
{
    public class SampleCode
    {
        public var sampleGreeting:String;
        public function sampleFunction()
        {
            trace(sampleGreeting + " from sampleFunction()");
        }
    }
}

在本例中,该类的名称是 SampleCode。由于该类位于 samples 包中,因此编译器在编译时会自动将其类名称限定为完全限定名称:samples.SampleCode。编译器还限定任何属性或方法的名称,以便 sampleGreetingsampleFunction() 分别变成 samples.SampleCode.sampleGreetingsamples.SampleCode.sampleFunction()

许多开发人员(尤其是那些具有 Java 编程背景的人)可能会选择只将类放在包的顶级。但是,ActionScript 3.0 不但支持将类放在包的顶级,而且还支持将变量、函数甚至语句放在包的顶级。此功能的一个高级用法是,在包的顶级定义一个命名空间,以便它对于该包中的所有类均可用。但是,请注意,在包的顶级只允许使用两个访问说明符:publicinternal。Java 允许将嵌套类声明为私有,而 ActionScript 3.0 则不同,它既不支持嵌套类也不支持私有类。

但是,在其它许多方面,ActionScript 3.0 中的包与 Java 编程语言中的包非常相似。从上一个示例可看出,完全限定的包引用点运算符 (.) 来表示,这与 Java 相同。可以用包将代码组织成直观的分层结构,以供其他程序员使用。这样,您就可以将自己所创建的包与他人共享,还可以在自己的代码中使用他人创建的包,从而推动了代码共享。

使用包还有助于确保所使用的标识符名称是唯一的,而且不与其它标识符名称冲突。事实上,有些人认为这才是包的主要优点。例如,假设两个希望相互共享代码的程序员各创建了一个名为 SampleCode 的类。如果没有包,这样就会造成名称冲突,唯一的解决方法就是重命名其中的一个类。但是,使用包,就可以将其中的一个(最好是两个)类放在具有唯一名称的包中,从而轻松地避免了名称冲突。

您还可以在包名称中嵌入点来创建嵌套包,这样就可以创建包的分层结构。Flash Player API 提供的 flash.xml 包就是一个很好的示例。flash.xml 包嵌套在 Flash 包中。

flash.xml 包中包含在早期的 ActionScript 版本中使用的旧 XML 分析器。该分析器现在之所以包含在 flash.xml 包中,原因之一是,旧 XML 类的名称与一个新 XML 类的名称冲突,这个新 XML 类实现 ActionScript 3.0 中的 XML for ECMAScript (E4X) 规范功能。

尽管首先将旧的 XML 类移入包中是一个不错的主意,但是旧 XML 类的大多数用户都会导入 flash.xml 包,这样,除非您总是记得使用旧 XML 类的完全限定名称 (flash.xml.XML),否则同样会造成名称冲突。为避免这种情况,现在已将旧 XML 类命名为 XMLDocument,如下面的示例所示:

package flash.xml
{
    class XMLDocument {}
    class XMLNode {}
    class XMLSocket {}
}

大多数 Flash Player API 都划分到 flash 包中。例如,flash.display 包中包含显示列表 API,flash.events 包中包含新的事件模型。

创建包

ActionScript 3.0 在包、类和源文件的组织方式上具有很大的灵活性。早期的 ActionScript 版本只允许每个源文件有一个类,而且要求源文件的名称与类名称匹配。ActionScript 3.0 允许在一个源文件中包括多个类,但是,每个文件中只有一个类可供该文件外部的代码使用。换言之,每个文件中只有一个类可以在包声明中进行声明。您必须在包定义的外部声明其它任何类,以使这些类对于该源文件外部的代码不可见。在包定义内部声明的类的名称必须与源文件的名称匹配。

ActionScript 3.0 在包的声明方式上也具有更大的灵活性。在早期的 ActionScript 版本中,包只是表示可用来存放源文件的目录,您不必用 package 语句来声明包,而是在类声明中将包名称包括在完全限定的类名称中。在 ActionScript 3.0 中,尽管包仍表示目录,但是它现在不只包含类。在 ActionScript 3.0 中,使用 package 语句来声明包,这意味着您还可以在包的顶级声明变量、函数和命名空间,甚至还可以在包的顶级包括可执行语句。如果在包的顶级声明变量、函数或命名空间,则在顶级只能使用 publicinternal 属性,并且每个文件中只能有一个包级声明使用 public 属性(无论该声明是类声明、变量声明、函数声明还是命名空间声明)。

包的作用是组织代码并防止名称冲突。您不应将包的概念与类继承这一不相关的概念混淆。位于同一个包中的两个类具有共同的命名空间,但是它们在其它任何方面都不必相关。同样,在语义方面,嵌套包可以与其父包无关。

导入包

如果您希望使用位于某个包内部的特定类,则必须导入该包或该类。这与 ActionScript 2.0 不同,在 ActionScript 2.0 中,类的导入是可选的。

以本章前面的 SampleCode 类示例为例。如果该类位于名为 samples 的包中,那么,在使用 SampleCode 类之前,您必须使用下列导入语句之一:

import samples.*;

或者

import samples.SampleCode;

通常,import 语句越具体越好。如果您只打算使用 samples 包中的 SampleCode 类,则应只导入 SampleCode 类,而不应导入该类所属的整个包。导入整个包可能会导致意外的名称冲突。

还必须将定义包或类的源代码放在类路径 内部。类路径是用户定义的本地目录路径列表,它决定了编译器将在何处搜索导入的包和类。类路径有时称为"生成路径"或"源路径"。

在正确地导入类或包之后,可以使用类的完全限定名称 (samples.SampleCode),也可以只使用类名称本身 (SampleCode)。

当同名的类、方法或属性会导致代码不明确时,完全限定的名称非常有用,但是,如果将它用于所有的标识符,则会使代码变得难以管理。例如,在实例化 SampleCode 类的实例时,使用完全限定的名称会导致代码冗长:

var mySample:samples.SampleCode = new samples.SampleCode();

包的嵌套级别越高,代码的可读性越差。如果您确信不明确的标识符不会导致问题,就可以通过使用简单的标识符来提高代码的可读性。例如,如果在实例化 SampleCode 类的新实例时仅使用类标识符,代码就会简短得多。

var mySample:SampleCode = new SampleCode();

如果您尝试使用标识符名称,而不先导入相应的包或类,编译器将找不到类定义。另一方面,即便您导入了包或类,只要尝试定义的名称与所导入的名称冲突,也会产生错误。

创建包时,该包的所有成员的默认访问说明符是 internal,这意味着,默认情况下,包成员仅对其所在包的其它成员可见。如果您希望某个类对包外部的代码可用,则必须将该类声明为 public。例如,下面的包包含 SampleCode 和 CodeFormatter 两个类:

// SampleCode.as 文件
package samples
{
    public class SampleCode {}
}

// CodeFormatter.as 文件
package samples
{
    class CodeFormatter {}
}

SampleCode 类在包的外部可见,因为它被声明为 public 类。但是,CodeFormatter 类仅在 samples 包的内部可见。如果您尝试访问位于 samples 包外部的 CodeFormatter 类,将会产生一个错误,如下面的示例所示:

import samples.SampleCode;
import samples.CodeFormatter;
var mySample:SampleCode = new SampleCode(); // 正确,public 类
var myFormatter:CodeFormatter = new CodeFormatter(); // 错误

如果您希望这两个类在包外部均可用,必须将它们都声明为 public。不能将 public 属性应用于包声明。

完全限定的名称可用来解决在使用包时可能发生的名称冲突。如果您导入两个包,但它们用同一个标识符来定义类,就可能会发生名称冲突。例如,请考虑下面的包,该包也有一个名为 SampleCode 的类:

package langref.samples
{
    public class SampleCode {}
}

如果按如下方式导入两个类,在引用 SampleCode 类时将会发生名称冲突:

import samples.SampleCode;
import langref.samples.SampleCode;
var mySample:SampleCode = new SampleCode(); // 名称冲突

编译器无法确定要使用哪个 SampleCode 类。要解决此冲突,必须使用每个类的完全限定名称,如下所示:

var sample1:samples.SampleCode = new samples.SampleCode();
var sample2:langref.samples.SampleCode = new langref.samples.SampleCode();

 

具有 C++ 背景的程序员通常会将 import 语句与 #include 混淆。#include 指令在 C++ 中是必需的,因为 C++ 编译器一次处理一个文件,而且除非显式包括了头文件,否则将不会在其它文件中查找类定义。ActionScript 3.0 有一个 include 指令,但是它的作用不是为了导入类和包。要在 ActionScript 3.0 中导入类或包,必须使用 import 语句,并将包含该包的源文件放在类路径中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值