InfoQ

文章

Java程序员ActionScript 3入门

作者 Jack Herrington 译者 张凯峰 发布于 2008年11月6日 上午3时21分

社区
Java
主题
RIA,
富客户端/桌面
标签
Flex,
ActionScript

我们还是勇敢面对吧:客户端对于Java程序员来说,一直都不是个友好的地方。Java在客户端的技术,包括applet、Swing和JavaFX到目前为止只取得了有限的成绩。JavaScript除了它的名字外,几乎没有什么地方像Java语言。而Adobe Flash呢,它看起来的确像JavaScript,真的吗?也许在几年前说Flash就像JavaScript一样是可以理解的,但随着 ActionScript 3的出现,一切都改变了。而且我相信你会喜欢它的很多东西。

首先,ActionScript这门针对Adobe Flex和Flash的编程语言,现在是强类型的了。它也是一流的面向对象语言,包括有类和接口。它还拥有你在Java中找不到的东西——特别地,它包含属性的getset方法,以及一个叫做ECMAScript for XML(E4X)的语言扩展,可以将任何XML文档转换成对象,这样你就可以通过“.”操作符直接引用它们,就跟普通对象一样。

这篇文章会引领你浏览ActionScript的基础内容,以及展示它与你所熟悉的Java环境的不同。到最后,你就会放弃你对ActionScript 的任何偏见,并开始有兴趣把玩它。关于Flex、Flash和ActionScript的最伟大的事情之一就是它们完全是免费的。只要下载了Adobe Flex Builder 3就可以开始了。Flex Builder是一个复杂的集成开发环境(IDE),而且不是免费的,但它用于构建Flash应用的Flex软件开发工具包(SDK)是完全免费的。

对阅读本文章的语言发烧友的一句忠告是:我并不是个语言教师,因此我可能忽略掉一些语言的细节。我也不会在这篇文章中演示ActionScript 3的所有内容。如果你的确需要这方面的内容,有很多非常棒的ActionScript 3的书籍。我能给予你的就是你对这门语言的初次的感觉。让我们开始吧。

类和接口

就和Java一样,在ActionScript 3中一切皆是对象。虽然有一些基本类型,比如integer,但除了这些,一切皆是对象。类似地,就像Java一样,ActionScript也有命名空间和包,比如com.jherrington.animals,其表示了company/jack herrington/animal下的类。你可以把类放到缺省的命名空间,但更好的方法是由你自己来控制自己的命名空间。

要定义一个类,你要使用class关键字,这也跟Java一样。请看示例:

package com.jherrington.animals
 {
 	public class Animal
 	{
 		public function Animal()
 		{
 		}
 	}
 }

在这个例子中,我定义了一个Animal类,以及什么也没干的构造函数。我还可以很容易地添加一些成员变量并完善这个构造函数,请看示例:

package com.jherrington.animals
 {
 	public class Animal
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private function Animal( _name:String, _age:int = 30 )
 		{
 			name = _name;
 			age = _age;
 		}
 	}
 }

这里,我给一个Animal对象定义了两个成员变量:name,一个公有的字符串,以及age,一个私有的整数。(很明显,小动物们对于它们的年龄都很害羞。:) )构造函数可以接受一个或两个参数:要么是单独的name,要么name和age。你也可以在函数声明中为参数提供缺省的值。

你会注意到这里的类型定义是跟Java相反的。在Java中,类型在变量之前;而在ActionScript中,类型在变量之后。这是因为强类型定义是追加到ActionScript上的。所以为了支持旧的、没有定义类型的代码,类型就需要放在变量名的后面。

让我添加一些方法来扩展这个示例:

package com.jherrington.animals
 {
 	import flash.geom.Point;

 	public class Animal
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private var location:Point = new Point(0,0);

 		public function Animal( _name:String, _age:int = 30 )
 		{
 			name = _name;
 			age = _age;
 		}

 		public function moveTo( x:int, y:int ) : void {
 			location.x = x;
 			location.y = y;
 		}

 		public function getLocation( ) : Point {
 			return location;
 		}
 	}
 }

正如你所看到的,我又添加了一个私有成员变量location,类型是我从Flash的geometry包中引入的Point类型。而且我还添加了两个方法来操作location:moveTo,用来移动animalgetLocation,用来返回当前的位置。

到目前为止,这还是以Java的方式去get和set一个值。但ActionScript方式会清晰很多,请看示例:

package com.jherrington.animals
{
 	import flash.geom.Point;

 	public class Animal
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private var myLocation:Point = new Point(0,0);

 		public function Animal( _name:String, _age:int = 30 )
 		{
 			name = _name;
 			age = _age;
 		}

 		public function set location( pt:Point ) : void {
 			myLocation = pt;
 		}

 		public function get location( ) : Point {
 			return myLocation;
 		}
 	}
 }

这里我使用getset函数,它们会在客户代码获取或设置成员变量location时被调用。对于客户代码来说,location变量看起来就像是个普通的成员变量。但事实上,你可以用你喜欢的任何代码来响应成员变量的设值,以及处理变量的获取。

如何来使用它呢?你可以添加一个事件,这个事件会在location发生改变时被触发。请看示例代码:

package com.jherrington.animals
{
  	import flash.events.Event;
 	import flash.events.EventDispatcher;
 	import flash.geom.Point;

 	public class Animal extends EventDispatcher
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private var myLocation:Point = new Point(0,0);

 		public function Animal( _name:String, _age:int = 30 )

 			name = _name;
 			age = _age;
 		}

 		public function set location ( pt:Point ) : void {
 			myLocation = pt;
 			dispatchEvent( new Event( Event.CHANGE ) );
 		}

 		public function get location( ) : Point {
 			return myLocation;
 		}
 	}
 }

现在,我指定Animal类是一个事件分发者——也就是说,客户代码可以从这个对象监听到事件发生。接着,当location改变时,我发出了一个新的事件。

下面就是客户代码,它创建了一个animal对象,并开始监听事件是否发生,然后就改变了animallocation

	var a:Animal = new Animal();
 	a.addEventListener(Event.CHANGE, function( event:Event ) : void {
 		trace( "The animal has moved!" );
 	} );
 	a.location = new Point( 10, 20 );

这段代码在animal移动时会记录一条跟踪信息。在ActionScript中,你可以定义任何类型的消息。大多数的类都是EventDispatcher类,你可以为它们的事件添加监听器。

接口

就像Java一样,ActionScript 3语言也支持接口,并使用类来实现它们。下面的示例中,就是一个我们可以用Animal类来实现的接口:

package com.jherrington.animals
 {
 	import flash.geom.Point;

 	public interface IAnimal
 	{
 		function get name() : String;
 		function set name( n:String ) : void;

 		function get location() : Point;
 		function set location( pt:Point ) : void;
 	}
 }

在这个例子中,我为接口定义了两个可以set和get的成员变量。没错,你可以在ActionScript接口中定义方法和成员变量。是不是很酷?

为了实现这个接口,我对Animal类做了一点修改。请看示例:

package com.jherrington.animals
 {
 	import flash.events.Event;
 	import flash.events.EventDispatcher;
 	import flash.geom.Point;

 	public class Animal extends EventDispatcher implements IAnimal
 	{
 		private var myName:String = "";

 		public function get name() : String
 		{
 			return myName;
 		}
 		public function set name( n:String ) : void
 		{
 			myName = n;
 			dispatchEvent( new Event( Event.CHANGE ) );
 		}
 		private var myLocation:Point = new Point(0,0);

 		public function set location ( pt:Point ) : void {
 			myLocation = pt;
 			dispatchEvent( new Event( Event.CHANGE ) );
 		}

 		public function get location( ) : Point {
 			return myLocation;
 		}

 		public function Animal( _name:String )
 		{
 			name = _name;
 		}
 	}
 }

当然,我也可以为这个类添加特定的变量和方法,或者实现除了IAnimal接口之外的其他接口。但是和Java一样,我只能继承一个基类。

静态和常量

ActionScript 3支持常量和静态成员变量,以及静态方法。常量定义起来很方便,请看示例:

		public const MINIMUM_AGE:int = 0;
  		public const MAXIMUM_AGE:int = 2000;

常量可以是你期望的任何类型,但它们必须是在编译时定义。如果你愿意,你也可以把它们定义成受保护的或者是私有的作用域。

为了演示一下静态方法,我在Animal类中写了一个工厂方法:

		public static function buildAnimal( n:String ) : IAnimal {
 			return new Animal( n );
 		}

使用静态方法的另外一种方式是单例模式。下面就是一个针对Animal类的单例工厂类:

package com.jherrington.animals
 {
 	public class AnimalFactory
 	{
 		private static var _factory:AnimalFactory = new AnimalFactory();

 		public static function get instance() : AnimalFactory {
 			return _factory;
 		}

 		public function build( n:String ) : Animal {
 			return new Animal( n );
 		}
 	}
 }

我使用该单例工厂的instance成员变量来获得其对象,并调用它:

private var b:Animal = AnimalFactory.instance.build( "Russell" );

这句代码使用单例工厂对象创建了一个新的名叫Russell的animal对象。

继承

为了演示继承,我写了三个接口和类。第一个是之前的IAnimal接口,第二个是Animal类,第三个是名叫Dog的继承类,它覆写了一个方法。

接口IAnimal定义如下:

	public interface IAnimal
 	{
 		function get name() : String;
 		function set name( n:String ) : void;

 		function move( x:int, y:int ) : void;
 	}

我对它进行了简化,这样它只有一个name成员变量和一个move()方法。第一个实现这个接口的是Animal类:

public class Animal extends EventDispatcher implements IAnimal
 {
 	private var myName:String = "";

 	public function get name() : String
 	{
 		return myName;
 	}
 	public function set name( n:String ) : void
 	{
 		myName = n;
 		dispatchEvent( new Event( Event.CHANGE ) );
 	}

 	public function Animal( _name:String )
 	{
 		name = _name;
 	}

 	public virtual  function move( x:int, y:int ) : void
 	{
 	}
 }

然后,Dog类在Animal类的基础上构建起来,它具有自己的构造函数,并覆写了move()方法:

public class Dog extends Animal
 {
 	public function Dog(_name:String)
 	{
 		super(_name);
 	}

 	public override function move( x:int, y:int ) : void
 	{
 		trace( 'Moving to '+x+', '+y );
 	}
 }

这看起来非常像Java代码,所以你会感觉到用ActionScript来实现自己的面向对象设计会非常轻松。

操作符和条件语句

ActionScript中的操作符和你在Java中看到的完全一样。类似地,算术和布尔操作符也是一样的:

	var a:int = 5;
 	var b:int = 6;
 	var c:int = a * b;
 	c *= 10;
 	var d:Boolean = ( c > 10 );
 	var e:int = d ? 10 : 20;

这些实例演示了一些不同的操作符。在这些示例中,ActionScript和Java的唯一不同在于定义变量的语法不一样。

跟操作符一样,条件语句也是完全一样的,请看示例:

	if ( a > 10 ) {
 		trace( 'low' );
 	}
 	else if ( a > 20 ) {
 		trace( 'high' );
 	}
 	else {
 		threw new Exception( "Strange value" );
 	}

这里演示了条件语句的语法,以及如何抛出异常。异常处理和Java中的完全一样。你可以定义自己的异常类型,或者直接使用标准的Exception类。

下面是trycatchfinally语法的使用:

	try
 	{
 		location = new Point( -10, 10 );
 	}
 	catch( Exception e )
 	{
 		trace( e.toString() );
 	}
 	finally
 	{
 		location = null;
 	}

这段代码试图设置location,并在错误发生时跟踪错误信息。不管哪种情况,最终,location都会被设为null

迭代

ActionScript 3没有强类型的容器类,但数组和哈希表使用起来还是非常容易的。这里是一个使用for循环来迭代一个数组的例子:

	var values:Array = new [ 1, 2, 5 ];
 	for( var i:int = 0; i < values.length; i++ )
 		trace( values[i] );

但这并不是你在ActionScript中迭代数组应该使用的方式。最好的方式是使用for each语法,请看示例:

	var values:Array = new [ 1, 2, 5 ];
 	for each ( var i:int in values )
 		trace( i );

这段代码迭代访问数组中的每个元素,并把i的值设置为每个元素的值。

要创建一个哈希表,你可以使用ActionScript中基本的Object类型:

	var params:Object = { first:'Jack', last:'Herrington' };
 	for( var key:String in params )
 		trace( key+' = '+params[key] );

ActionScript起源于JavaScript意味着基础对象类型是基于插槽(slots-based)的容器,这样你可以轻而易举地把它作为哈希表来使用。

正则表达式

正则表达式是ActionScript中的基础语法。比如下面这段代码:

	if ( name.search( /jack/i ) )
 	{
 		trace('hello jack');
 	}

是对一个字符串的简单检查。

这段代码是使用正则表达式来执行分割操作:

	var values:String = "1,2,3";
 	for each( var val:String in values.split(/,/) ) {
 		trace( val );
 	}

你是否应该把正则表达式嵌在自己的核心代码里面,是值得商榷的。Java的架构师们显然认为这些表达式应该留在一个外部的库中。但我认为,它们非常有用,所以它们应该像在ActionScript中这样被集成。

E4X

XML应用得很广泛,以至于ActionScript直接把它构建在语言的语法里面以示支持。如果你是个XML爱好者,你会非常喜欢这个的。请看示例:

var myData:XML = <names>
 	<name>Jack</name>
 	<name>Oso</name>
 	<name>Sadie</name>
 </names>;
 	for each ( var name:XML in myData..name ) {
 		trace( name.toString() );
 }

这段代码定义了一个XML文档,然后对它进行搜索并打印出所有的标签

下面这段代码也是获取<name> 标签,但只获取那些type是dog的标签。

var myData:XML = <names>
 	<name type="person">Jack</name>
 	<name type="dog">Oso</name>
 	<name type="dog">Sadie</name>
 </names>;
 	for each ( var name:XML in myData..name.(@type='dog') ) {
 		trace( name.toString() );
 }

@语法有点类似于XPath和XSLT。它用来指定我们要查看的是属性而不是XML元素本身。

E4X是对这门语言的梦幻增强。它把XML解析从繁琐变成了轻松愉快的事情。Web services甚至也可以以E4X的格式返回以便于解析。

总结

Adobe对于ActionScript做了一些非凡的改进。它是一门比人们想象的成熟得多的语言。我认为你会最终发现Adobe所做的,就是吸取了Java的得失教训,并把它们合并进ActionScript 3语言的开发中。你会很乐意看到最后的结果。

获取更多的信息

  • 要获取更多关于ActionScript和Java语法的相似性,请阅读Yakov Fain的文章,"Comparing the syntax of Java 5 and ActionScript 3" (JDJ, 2006年11月12日)。
  • 可以从Open Source Flash下载到Java-to-ActionScript转换器,这样你就可以使用Java而不是ActionScript来创建Flash内容了。
  • 要寻找资源列表来帮助你在ActionScript、Flex、Java和JavaScript开发之间游走,请查看RIAdobe的比较列表。
  • Flex.org上有你想知道的关于Adobe Flex的一切。

志愿参与InfoQ中文站内容建设,请邮件至editors@cn.infoq.com。也欢迎大家到InfoQ中文站用户讨论组参与我们的线上讨论。

学习 发表人 wang arlin 发表于 2008年11月8日 下午8时37分
Re: 学习 发表人 sailor sailor 发表于 2008年11月9日 下午9时10分
Re: 学习 发表人 Zheng Luo 发表于 2008年11月11日 上午6时55分
Re: 学习 发表人 GX Wang 发表于 2008年11月11日 上午7时20分
Re: 学习 发表人 hu wei 发表于 2008年12月9日 下午7时45分
疑问 发表人 qi liu 发表于 2008年11月10日 下午11时28分
Re: 疑问 发表人 xiaoping chen 发表于 2008年11月11日 上午5时40分
整个就是Java+Pascal+JavaScript的混合物 发表人 delphi doc 发表于 2008年11月11日 下午7时40分
继续学习! 发表人 伟 张 发表于 2008年11月12日 上午1时41分
Java程序员ActionScript 3入门 发表人 ming xie 发表于 2008年11月13日 上午4时12分
l 发表人 奇 翁 发表于 2008年11月14日 上午5时12分
不错的文章 发表人 jun ji 发表于 2008年11月15日 上午1时6分
学习. 发表人 Xu Zhang 发表于 2008年11月16日 下午9时34分
Java程序员ActionScript 3入门 发表人 bobby yao 发表于 2008年11月16日 下午10时46分
Re: Java程序员ActionScript 3入门 发表人 li Fangzhao 发表于 2008年11月20日 下午8时33分
Re: Java程序员ActionScript 3入门 发表人 li Fangzhao 发表于 2008年11月20日 下午8时46分
  1. 返回顶部

    学习

    2008年11月8日 下午8时37分 发表人 wang arlin

    笔者也说了 不讲语言 不过通过笔者给的例子我们可以很容易的看到actionscript的强大,作为java程序员 很容易入手 所以我会继续学习学习 不知道javaFX的出现会给我们带来什么 javascript需要做的还有很多 但现在对我来说足够了。 我想问一下c*这个是否是指针 ?

  2. 返回顶部

    Re: 学习

    2008年11月9日 下午9时10分 发表人 sailor sailor

    ActionScript 跟C#类似

  3. 返回顶部

    疑问

    2008年11月10日 下午11时28分 发表人 qi liu

    从没接触过的角度问下: 例如我们可在jsp中的混合java,在jsp服务器负责翻译jsp为servlet。在Flex中能吗,是否需要类似服务器呢?

  4. 返回顶部

    Re: 疑问

    2008年11月11日 上午5时40分 发表人 xiaoping chen

    2年前我研究过那时候的FLEX,那时候,tomcat+flex的插件,就可以通过tomcat来执行flex程序的程序,好像有个flex builder可以可视化操作。他的语言使用mxml开始的还是什么,很久没有研究了

  5. 返回顶部

    Re: 学习

    2008年11月11日 上午6时55分 发表人 Zheng Luo

    C *= 10 == C = C * 10

  6. 返回顶部

    Re: 学习

    2008年11月11日 上午7时20分 发表人 GX Wang

    学习...

  7. 返回顶部

    整个就是Java+Pascal+JavaScript的混合物

    2008年11月11日 下午7时40分 发表人 delphi doc

    整个就是Java+Pascal+JavaScript的混合物

  8. 返回顶部

    继续学习!

    2008年11月12日 上午1时41分 发表人 伟 张

    继续学习!

  9. 返回顶部

    Java程序员ActionScript 3入门

    2008年11月13日 上午4时12分 发表人 ming xie

    这个网站,真好!

  10. 返回顶部

    l

    2008年11月14日 上午5时12分 发表人 奇 翁

    挺好

  11. 返回顶部

    不错的文章

    2008年11月15日 上午1时6分 发表人 jun ji

    大家有机会可以到AIRIA的论坛里交流FLEX。BBS.AIRIA.CN

  12. 返回顶部

    学习.

    2008年11月16日 下午9时34分 发表人 Xu Zhang

    对flex 技术完全是新手 甚至够不到新手 因为在java方面也才顶多算个刚起步或者其他什么 因此要学的东西还很多 infoq.com 太棒了 总能给你你想要的 你想知道的...

  13. 返回顶部

    Java程序员ActionScript 3入门

    2008年11月16日 下午10时46分 发表人 bobby yao

    我刚刚接触了下flex,发现跟java真的很相似。但是还有很多地方需要改进一下,比如说arraycollection的一些方法不太好用,很多时候都需要跌代,参数传递都是传指针。这样有很多的优点但是也带来了一些不便。

  14. 返回顶部

    Re: Java程序员ActionScript 3入门

    2008年11月20日 下午8时33分 发表人 li Fangzhao

    接触Flex一年半了,确实爱恨参半。 总之,客户端的脚本语言,我们不可能期望它做太多。 追求的是美观甚至炫酷的界面效果,同样,对操作系统的资源占用相对就高一些。不过对于目前的硬件普遍水平而言,基本上没什么障碍。 至于服务器那边的核心业务逻辑与数据存读,Java代码该怎么优化还怎么优化吧,这已经不是Flex的职责范围了。

  15. 返回顶部

    Re: Java程序员ActionScript 3入门

    2008年11月20日 下午8时46分 发表人 li Fangzhao

    顺便再提一下: 译文中E4X的部分 for each ( var name:XML in myData..name.(@type='dog') ) @type='dog' 缺了一个"="号 应该是 @type=='dog' 才对。

  16. 返回顶部

    Re: 学习

    2008年12月9日 下午7时45分 发表人 hu wei

    c *= 10 中的c*怎么会是指针呢?你学过java应该知道 c += 10,c -= 10,类似的运算符吧,c *= 10 就是c = c*10;

深度内容

和Google互补的搜索引擎Wolfram|Alpha

Wolfram|Alpha与Google究竟是什么关系,Wolfram|Alpha自己是如何定位的?Wolfram|Alaph在多大程度上是语义网搜索呢?InfoQ中文站就等等这些问题采访了Wolfram研究公司中国区商务经理王翔。

SOA契约成熟度模型

本文说明了所推荐的契约版本管理设计策略是如何与SOA成熟度模型发生联系的。文章目的是为实现版本管理和可组合性提供一个路线图。

数据服务简介

Vijay Narayanan在这篇文章中对数据服务的几个方面进行了介绍,它们都是SOA实践者和数据架构师感兴趣的内容。本文对数据服务的几个方面进行了介绍,包括需求定义,基本原理和好处、范围、开发以及消费模式。

分块云计算

在本文中,Jimmy Nilsson描述了一种他在过去数年间观察到的一种正在缓慢成长的架构风格,他把这种风格称为“分块云计算”。

豆瓣网技术架构变迁

罗马不是一天建成的,豆瓣的技术架构也是随着用户规模的增长一直在持续变化中。在本次演讲中,豆瓣的首席架构师洪强宁将与大家一起分享从上线时的单台服务器架构开始一直到现在的豆瓣架构变迁历程。

融合思想:深入探索S#arp架构

Billy McCafferty展示了S#arp架构,它在ASP.NET MVC框架的基础上,荟萃了当今的最佳实践,应用在ASP.NET Web应用程序的架构设计中。

王雷谈开源以及新兴市场计划

中国作为新兴市场中的新兴市场,是Sun在美国之外实施SSE(SUN Startup Essentials)项目重点关注的地区。在QCon Beijing 2009期间,InfoQ中文站有幸对此项目的负责人王雷先生进行了采访,探讨了关于开源、新兴市场、SSE等话题。

使用HTML5构建下一代的Web Form

HTML5 是由 WHATWG发起的,最开始的名称叫做Web Application 1.0,而后这个标准吸纳了Web Forms 2.0的标准,并一同被W3C组织所采用,合并成为下一代的HTML5标准。