属性名を使ったアクセス
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番目の要素が追加される