属性名を使ったアクセス
Javaでは、フィールドへのアクセスには、「ドット(.)+フィールド名」を使います。
public class Foo
{
public int bar;
}
Foo foo = new Foo();
foo.bar = 1;
既に見てきたように、AS3の属性へのアクセスも、同様のシンタックスを使います。しかし、AS3にはもう1つ、属性名の文字列を使って、属性にアクセスするという方法も用意されています。
public class Foo {
public var bar:int;
}
var foo:Foo = new Foo();
// 以下は同じ意味
foo.bar = 1;
foo["bar"] = 1;
このサンプルのように、オブジェクト名に続いて[]内に属性名を記述します。属性名には変数を使うこともできます。
var foo:Foo = new Foo(); var name:String = "bar"; foo[name] = 1;
リフレクション(属性)
Javaも、リフレクションの機能を使うと文字列を使ってフィールドにアクセスすることができます。
Class c = foo.getClass(); String name = "bar"; Field f = c.getField(name); f.set(foo, 1);
このように、リフレクションを利用すると実行時にアクセスするフィールドを選択できるため、より柔軟性の高いコードを記述できます。しかし、通常の記述に比べてコードが複雑で読みにくくなってしまうことなどにより、リフレクションの使用はあまり一般的ではありません。
一方、上で触れたように、AS3では同様の記述が1行で済みます。Javaのようにはコードの保守性を損なわないため、実行時にアクセスするフィールドを選択する、という記述が使いやすくなっています。
foo[name] = 1;
存在しない属性へのアクセス
Javaでフィールドに直接アクセスする場合、存在しないフィールド名を指定すると、コンパイルエラーになります。
public class Foo {}
Foo foo = new Foo();
foo.bar = 1;
// Foo にはフィールドが無いため、コンパイルエラーになる
これは、AS3でも同じです。
public class Foo {}
var foo:Foo = new Foo();
foo.bar = 1;
// Foo には属性が無いため、コンパイルエラーになる
しかし、属性名を使って、属性にアクセスする場合、コンパイル時にフィールドの有無のチェックが行われません。存在しない属性名が指定された場合は、ランタイムエラーになります。
var foo:Foo = new Foo(); foo["bar"] = 1; // Foo にはフィールドが無いため、ランタイムエラーになる
Map
Object
Javaでは、コレクションフレームワークにMapが含まれます。Mapは指定された型のオブジェクトをキーとして値を管理する機能を提供します。例えば、下はStringをキーとするHashMapを使って、String型の値を管理する例です。
HashMap<String,String> map = new HashMap<String,String>();
String bar = "bar";
map.put("foo", bar)
// "foo"に対応する値を取得する
Object value = map.get("foo");
AS3では、ObjectがMapの機能を持っています。キーとして使えるオブジェクトはStringに限定されます。一方、値は任意の型になります。
var obj:Object = new Object(); var bar:String = "bar"; obj["foo"] = bar; // "foo"に対応する値を取得する var value:Object = obj["foo"];
ところで、上のサンプル内の記述方法は、クラスの属性にアクセスする場合と同じ["属性名"]です。通常のクラスでは、属性名で指定した属性が存在しなければ、ランタイムエラーになります。しかし、Objectの場合は、任意の名前の指定が可能です。このことから、Objectは、実行時に属性を追加することができるクラス、と考えることもできます。
Objectから、存在しないキーを指定して値を参照すると、undefinedが返されます。通常のクラスであればランタイムエラーが発生しているところです。
var obj:Object = new Object(); trace(obj["foo"]); // undefined が出力される
さらに、Objectの場合は下のような記述をしても、コンパイルエラーは発生しません。
var obj:Object = new Object(); trace(obj.foo); // undefined が出力される
ところで、AS3のObjectのインスタンスを初期化するのに、下のような書き方もできます。コロン(:)の前が要素名、後が要素の値です。要素間はカンマ(,)で区切ります。見た目にもMapの初期化っぽく見えます。
var obj:Object = { foo:10, bar:"Hello" };
Dictionary
AS3で任意のオブジェクトをキーとしてMapを使いたい場合、Dictionaryクラスを使います。
var map:Dictionary = new Dictionary(); var foo:Object = new Object(); map[foo] = "foo"; var value:Object = map[foo];
Dictionaryのキーは、値ではなくインスタンス自体です。同じ値をもつ同じ型のインスタンスでも、違うキーとして認識されます。下の例は、2つのObjectのインスタンスを使って、Dictionaryから値を取得しています。
var map:Dictionary = new Dictionary(); var foo:Object = new Object(); var bar:Object = new Object(); map[foo] = "foo"; trace(map[foo]); // fooが出力される trace(map[bar]); // undefinedが出力される
Dictionaryの詳細はASDocのDictionaryをご覧ください。
Array
AS3のArrayは数値をキーとしたMapのような動作をします。これは、JavaのArrayと大きく異なる点です。
例えば、Javaでは配列の大きさがインスタンス生成時に決まります。
Array arr = new Array(1); arr[0] = new Object(); arr[1] = new Object(); // ランタイムエラーが発生
AS3では、任意のキーを指定できます。
var arr:Array = []; arr[0] = new Object(); arr[10] = new Object(); // 10番目の要素が追加される

