この記事は、Javaに精通した開発者の方に、ActionScript 3.0(以下AS3)がどのような言語なのか、どこがJavaと異なっているのか(あるいは同じなのか)を一覧できるようまとめたものです。
主にAS3の静的な側面をまとめた、『文法編』(前回の記事)および『クラス宣言編』(Adobe Developer Connection『クラス宣言編』にて公開中)と、動的な側面をまとめた、『属性操作編』(この記事)および『振舞い編』(Adobe Developer Connection『振舞い編』にて公開中)の4編に分けて、Java開発者が引っかかりやすいと思われる点を中心に記述しました。
厳密な言語解説よりは、まずAS3の概要が分かること、を目的に書かれています。さらに詳しい言語仕様についてはActionScript 3.0の学習をご覧ください。
属性操作編の内容
属性操作編では、クラス宣言編で紹介した属性の使い方について、より深く掘り下げます。AS3の属性はJavaと異なり動的な要素を持っています。そのため、Javaでは一般的ではない使い方をすることもしばしばです。この記事では具体的な例を使いながら、AS3の属性の特徴と振舞いを紹介します。
まず、クラス宣言編でも紹介したアクセッサーの特徴をもう一度確認します。
アクセッサー
Javaでは、アクセッサーの使用はフィールドへの直接アクセスとは明確に区別されます。一方、AS3では、ほとんどの場合アクセッサーの使用を意識することはありません。そのため、AS3の方がクラスの仕様変更をより柔軟に行うことができます。
例えばJavaの場合、以下のように祝日の日数をpublic
な定数として、クラスFoo
に定義した場合を考えてみます。
public class Foo { // 国民の祝日は年に16日 public static int nationalHolidays = 16; }
このとき、クラスFoo
を利用する側では以下のようなコードを記述することになります。
// フィールドにアクセス int bar = Foo.nationalHolidays;
ところが、実は祝日の数が毎年変わることに後から気づいて(ちょっと間抜けな例ですが)、定数の代わりにゲッターを使って日数を取得させるよう変更したとします。この場合、クラスの使い方が変わってしまうため、上のコードはコンパイルが通らなくなります。
public class Foo { public static int getNationalHolidays() { // 現在の日付により、その年の休日数を返すよう変更 } }
そのため、Foo
を利用する側のコードは修正することになります。
// ゲッターを呼び出す int bar = Foo.getNationalHolidays();
このような変更作業を行わなければならないのは、あまり望ましいとは言えません。Javaではアクセッサーの実装がベストプラクティスとして推奨されているという理由もありますが、後からコードを修正することによるコストに対する問題意識から、最初の段階からアクセッサーを実装するのが一般的です。
一方、AS3では、途中からアクセッサーを実装するよう変更しても、それまでのコードが利用できます。例えば、上の例をAS3に置き換えた場合、クラスFoo
の実装をゲッターに変更すると、下のようになります。
public class Foo { public static function get nationalHolidays():int { // 現在の年に応じて休日数を返すよう変更 } }
しかし、ゲッターを呼び出す側の記述は、属性に直接アクセスするのと変わりません。
// ゲッターを呼び出す var bar:int = Foo.nationalHolidays;
このように、AS3はアクセッサーのへ変更を後から行いやすい仕様になっています。
AS3でも、アクセッサーの実装が好ましいことに変わりはありません。しかし、変更による影響が少ないため、まずあまり手間をかけずにプロトタイプを作ってしまいたい、その後でコードを洗練させたい、という開発が行いやすくなります。この点は、クライアントアプリ用に使われる言語としては、有利な特徴といえるでしょう。
属性の上書き
AS3で、アクセッサーの使用と属性の直接操作が区別されないという特徴は、他にもJavaにはない使い方を可能にします。属性のオーバーライドです。
Javaでは、子クラスで親クラスと同じ名前のフィールドを宣言すると、フィールドが再定義され、親クラスのフィールドは隠蔽されます。
class FooBase { String bar = "FooBase"; } class Foo extends FooBase { String bar = "Foo"; } FooBase foo1 = new Foo(); Foo foo2 = new Foo(); // 親クラスの変数として参照 System.out.println(foo1.bar); // FooBaseが出力される // 子クラスの変数として参照 System.out.println(foo2.bar); // Fooが出力される
AS3も基本的には同様で、var
またはconst
キーワードで宣言された属性をオーバーライドすることはできません。Javaと同じく別の属性定義として扱われます。
一方、get
やset
を使って宣言された属性は、アクセッサーをオーバーライドして、属性のオーバーライドと同等の機能を実現できます。下の例では、子クラスでセッターのオーバーライドをして、値が変更されたらイベントを発生させる機能を追加しています。
class FooBase { private var _bar:int; public function set bar(value:int):void { _bar = value; } public function get bar():int { return _bar; } } class Foo extends FooBase implements IEventDispatcher { override public function set bar(value:int):void { // 親クラスの set を呼び出し super.bar = value; // 変更をイベントとして伝える dispatchEvent(new Event(Event.CHANGE)); } ... }
これでbar
という属性を以下のように使うことができます。
Foo foo = new Foo(); foo.bar = 1; // ここでイベントが発生する trace(foo.bar); // 1
アクセッサーのオーバーライドについてはオンラインヘルプのgetterとsetterのオーバーライドもご覧ください。