Adobe Flex 3 ヘルプ

継承

継承は、コード再利用の一形式であり、プログラマは既存のクラスを基に新しいクラスを開発することができます。既存のクラスは「基本クラス」または「スーパークラス」と呼ばれますが、新しいクラスは通常「サブクラス」と呼ばれます。継承の主な利点は、既存のコードをそのまま維持しながら、基本クラスのコードを再利用できることです。さらに、継承では他のクラスが基本クラスとやり取りする方法を変更する必要がありません。入念にテストされたか、既に使用されている既存クラスを変更するのではなく、継承を使用することでそのクラスを追加プロパティまたはメソッドで拡張できる統合モジュールとして使用できます。このため、extends キーワードを使用して、クラスが別のクラスを継承することを示すことができます。

継承を使用すると、コード内で「ポリモーフィズム」を利用することもできます。ポリモーフィズムを使用すると、異なるデータ型に適用された場合に異なる動作を実行するメソッドに単一のメソッド名を使用できます。単純な例として、2 つのサブクラス Circle と Square を持つ Shape という名前の基本クラスがあります。Shape クラスは、形状の面積を返す area() というメソッドを定義します。ポリモーフィズムが実装されている場合、Circle 型および Square 型のオブジェクトで area() メソッドを呼び出して、正しい計算を行うことができます。継承では、サブクラスが基本クラスからメソッドを継承し再定義できるようにする、つまり「オーバーライド」を許可することで、ポリモーフィズムが有効になります。次の例では、area() メソッドを Circle クラスと Square クラスで再定義します。

class Shape
{
    public function area():Number
    {
        return NaN;
    }
}

class Circle extends Shape
{
    private var radius:Number = 1;
    override public function area():Number
    {
        return (Math.PI * (radius * radius));
    }
}

class Square extends Shape
{
    private var side:Number = 1;
    override public function area():Number
    {
        return (side * side);
    }
}

var cir:Circle = new Circle();
trace(cir.area()); // output: 3.141592653589793
var sq:Square = new Square();
trace(sq.area()); // output: 1

各クラスはデータ型を定義するため、継承を使用すると、基本クラスと基本クラスを拡張するクラスの特別な関係が作成されます。サブクラスは、基本クラスのすべてのプロパティを保有します。これは、サブクラスのインスタンスは常に基本クラスのインスタンスの代わりに使用できることを意味します。例えば、メソッドが Shape 型のパラメータを定義する場合、Circle 型は Shape 型を拡張するので Circle 型のパラメータを渡すことができます。次に例を示します。

function draw(shapeToDraw:Shape) {}

var myCircle:Circle = new Circle();
draw(myCircle);

サブトピック



インスタンスプロパティと継承

インスタンスプロパティは、functionvar または const キーワードのいずれで定義されたかに関係なく、プロパティが基本クラスの private 属性で宣言されていない限り、すべてのサブクラスに継承されます。例えば、Flash Player API の Event クラスには、すべてのイベントオブジェクトに共通するプロパティを継承する多数のサブクラスがあります。

一部の型のイベントでは、Event クラスにイベントを定義するために必要なすべてのプロパティが含まれます。これらの型のイベントでは、Event クラスで定義されたもの以外のインスタンスプロパティは必要ありません。こうしたイベントの例として、データが正常にロードされたときに発生する complete イベント、ネットワーク接続が確立されたときに発生する connect イベントなどがあります。

次の例は、サブクラスに継承されるプロパティおよびメソッドの一部を示す Event クラスからの抜粋です。プロパティが継承されるため、サブクラスのインスタンスはこれらのプロパティにアクセスできます。

public class Event
{
    public function get type():String;
    public function get bubbles():Boolean;
    ...

    public function stopPropagation():void {}
    public function stopImmediatePropagation():void {}
    public function preventDefault():void {}
    public function isDefaultPrevented():Boolean {}
    ...
}

その他の型のイベントには、Event クラスで使用できない固有のプロパティが必要です。これらのイベントは、Event クラスで定義されたプロパティに新しいプロパティを追加できるように、Event クラスのサブクラスを使用して定義されます。こうしたサブクラスには、mouseMove イベントおよび click イベントなど、マウス操作またはマウスクリックに関連付けられているイベントに固有のプロパティを追加する MouseEvent クラスなどがあります。次の例は、サブクラスにあるが基本クラスにはないプロパティの定義を示す MouseEvent クラスからの抜粋です。

public class MouseEvent extends Event
{
    public static const CLICK:String= "click";
    public static const MOUSE_MOVE:String = "mouseMove";
    ...

    public function get stageX():Number {}
    public function get stageY():Number {}
    ...
}

アクセス制御指定子と継承

プロパティが public キーワードで宣言された場合、このプロパティは任意の場所のコードから参照できます。つまり、public キーワードは、privateprotected および internal キーワードとは異なり、プロパティの継承に制限を加えません。

プロパティが private キーワードで宣言された場合、このプロパティは定義されたクラス内でのみ参照でき、サブクラスに継承されません。このビヘイビアは、旧バージョンの ActionScript とは異なります。旧バージョンでは、private キーワードは ActionScript 3.0 の protected キーワードのように動作します。

protected キーワードは、プロパティが、定義されたクラス内だけでなくすべてのサブクラスからも参照できることを示します。Java プログラミング言語の protected キーワードとは異なり、ActionScript 3.0 の protected キーワードでは同じパッケージ内の他のすべてのクラスからプロパティを参照できるわけではありません。ActionScript 3.0 では、サブクラスのみが protected キーワードで宣言されたプロパティにアクセスできます。また、protected プロパティは、サブクラスが基本クラスと同じパッケージ内にあるか別のパッケージ内にあるかに関係なく、サブクラスから参照できます。

プロパティが定義されているパッケージからしかプロパティを参照できないようにするには、internal キーワードを使用するか、またはアクセス制御指定子を一切使用しないようにします。internal アクセス制御指定子は、アクセス制御指定子が指定されていないときに適用されるデフォルトのアクセス制御指定子です。internal とマークされたプロパティは、同じパッケージ内にあるサブクラスにのみ継承されます。

次の例を使用して、各アクセス制御指定子がパッケージ境界を越えてどのように継承に影響するかを確認できます。次のコードは、AccessControl というメインアプリケーションクラスと Base および Extender というその他のクラス 2 つを定義します。Base クラスは foo パッケージ内にあり、Base クラスのサブクラスである Extender クラスは bar パッケージ内にあります。AccessControl クラスは Extender クラスのみを読み込み、Base クラスで定義されている str という変数にアクセスしようとする Extender のインスタンスを作成します。次の抜粋に示すようコードがコンパイルおよび実行されるように、str 変数は public として宣言されます。

// Base.as in a folder named foo
package foo
{
    public class Base
    {
        public var str:String = "hello"; // change public on this line
    }
}

// Extender.as in a folder named bar
package bar
{
    import foo.Base;
    public class Extender extends Base
    {
        public function getString():String {
            return str;
        }
    }
}

// main application class in file named AccessControl.as
package
{
    import flash.display.MovieClip;
    import bar.Extender;
    public class AccessControl extends MovieClip
    {
        public function AccessControl()
        {
            var myExt:Extender = new Extender();
            trace(myExt.str);// error if str is not public
            trace(myExt.getString()); // error if str is private or internal
        }
    }
}

この例のコンパイルおよび実行にその他のアクセス制御指定子がどのように影響を与えるかを確認するには、AccessControl クラスの次の行を削除またはコメントアウトした後で、str 変数のアクセス制御指定子を privateprotected または internal に変更します。

trace(myExt.str);// error if str is not public

変数のオーバーライド禁止

var または const キーワードで宣言されたプロパティは継承されますが、オーバーライドすることはできません。プロパティをオーバーライドすると、サブクラスでプロパティが再定義されます。オーバーライドできるプロパティの型は、メソッド、つまり function キーワードで宣言されたプロパティだけです。インスタンス変数をオーバーライドすることはできませんが、インスタンス変数の getter および setter メソッドを作成し、これらのメソッドをオーバーライドすることで、同じ機能を実現できます。詳細については、getter および setter のオーバーライドを参照してください。

メソッドのオーバーライド

メソッドをオーバーライドすると、継承されたメソッドの動作が再定義されます。静的メソッドは継承されず、オーバーライドすることはできません。しかし、次の 2 つの条件が満たされている場合、インスタンスメソッドはサブクラスに継承され、オーバーライドできます。

  • インスタンスメソッドが基本クラス内で final キーワードで宣言されていない。final キーワードがインスタンスメソッドで使用された場合、サブクラスによってメソッドがオーバーライドされないようにプログラマが意図的に指定したことを示します。
  • インスタンスメソッドが基本クラス内で private アクセス制御指定子で宣言されていない。基本クラス内でメソッドが private としてマークされている場合、基本クラスのメソッドはサブクラスから参照できないため、サブクラス内で同じ名前のメソッドを定義するときに override キーワードを使用する必要はありません。

上記の条件を満たすインスタンスメソッドをオーバーライドするには、サブクラス内のメソッドの定義は override キーワードを使用し、次の方法でメソッドのスーパークラスバージョンと一致する必要があります。

  • オーバーライドメソッドには、基本クラスのメソッドと同じレベルのアクセス制御が必要です。internal とマークされたメソッドには、アクセス制御指定子を持たないメソッドと同じレベルのアクセス制御が必要です。
  • オーバーライドメソッドには、基本クラスのメソッドと同じ数のパラメータが必要です。
  • オーバーライドメソッドのパラメータには、基本クラスのメソッドのパラメータと同じデータ型注釈が必要です。
  • オーバーライドメソッドには、基本クラスのメソッドと同じ戻り値の型が必要です。

ただし、オーバーライドメソッドのパラメータの名前は、パラメータの数および各パラメータのデータ型が一致していれば、基本クラスのパラメータの名前と一致する必要はありません。

super ステートメント

メソッドをオーバーライドするとき、多くのプログラマが、動作を完全に置き換えるのではなく、オーバーライドするスーパークラスメソッドの動作に追加したいと考えるでしょう。これには、サブクラス内のメソッドがそれ自体のスーパークラスバージョンを呼び出すメカニズムが必要です。super ステートメントは、直接のスーパークラスへの参照が含まれるそのようなメカニズムを提供します。次の例では、thanks() というメソッドを含む Base クラスと、thanks() メソッドをオーバーライドする Extender という Base クラスのサブクラスを定義します。Extender.thanks() メソッドは、super ステートメントを使用して Base.thanks() を呼び出します。

package {
    import flash.display.MovieClip;
    public class SuperExample extends MovieClip
    {
        public function SuperExample()
        {
            var myExt:Extender = new Extender()
            trace(myExt.thanks()); // output: Mahalo nui loa
        }
    }
}

class Base {
    public function thanks():String
    {
        return "Mahalo";
    }
}

class Extender extends Base
{
    override public function thanks():String
    {
        return super.thanks() + " nui loa";
    }
}

getter および setter のオーバーライド

スーパークラスで定義された変数をオーバーライドすることはできませんが、getter および setter をオーバーライドすることができます。例えば、次のコードは、Flash Player API の MovieClip クラスで定義された currentLabel という名前の getter をオーバーライドします。

package
{
    import flash.display.MovieClip;
    public class OverrideExample extends MovieClip
    {
        public function OverrideExample()
        {
            trace(currentLabel)
        }
        override public function get currentLabel():String
        {
            var str:String = "Override: ";
            str += super.currentLabel;
            return str;
        }
    }
}

OverrideExample クラスコンストラクタの trace() ステートメントの出力は Override: null で、この例では継承された currentLabel プロパティをオーバーライドできたことを示します。

継承されない静的プロパティ

静的プロパティはサブクラスに継承されません。つまり、サブクラスのインスタンスから静的プロパティにアクセスすることはできません。静的プロパティは、そのプロパティが定義されたクラスオブジェクトからのみアクセス可能です。例えば、次のコードは、Base という基本クラスと、Extender という Base クラスを拡張するサブクラスを定義します。静的変数 test は Base クラスで定義されています。次の抜粋のコードは、strict モードではコンパイルされず、standard モードではランタイムエラーを生成します。

package {
    import flash.display.MovieClip;
    public class StaticExample extends MovieClip
    {
        public function StaticExample()
        {
            var myExt:Extender = new Extender();
            trace(myExt.test);// error
        }
    }
}

class Base {
    public static var test:String = "static";
}

class Extender extends Base { }

静的変数 test にアクセスするには、次のコードに示すように、クラスオブジェクトからアクセスする必要があります。

Base.test;

静的プロパティと同じ名前を使用してインスタンスプロパティを定義することができます。このインスタンスプロパティは、静的プロパティと同じクラス内またはサブクラス内で定義できます。例えば、前述の例の Base クラスでは、test というインスタンスプロパティを定義できます。次のコードはコンパイルおよび実行されます。これは、インスタンスプロパティが Extender クラスに継承されるからです。test インスタンス変数の定義が Extender クラスにコピーされるのではなく、移動された場合も、コードはコンパイルされ、実行されます。

package
{
    import flash.display.MovieClip;
    public class StaticExample extends MovieClip
    {
        public function StaticExample()
        {
            var myExt:Extender = new Extender();
            trace(myExt.test);// output: instance
        }
    }
}

class Base
{
    public static var test:String = "static";
    public var test:String = "instance";
}

class Extender extends Base {}

静的プロパティとスコープチェーン

静的プロパティは継承されませんが、そのプロパティが定義されたクラスおよびそのクラスのサブクラスのスコープチェーン内にあります。このため、静的プロパティは、定義されたクラスおよびサブクラスの「スコープ内」にあると言います。つまり、静的プロパティが定義されたクラスおよびそのサブクラスの本体内から直接静的プロパティにアクセスできます。

次の例では、前述の例で定義したクラスを変更して、Base クラスで定義された静的変数 test が Extender クラスのスコープ内にあることを示します。つまり、Extender クラスは、test を定義したクラスの名前を接頭辞として変数に付けなくても静的変数 test にアクセスできます。

package
{
    import flash.display.MovieClip;
    public class StaticExample extends MovieClip
    {
        public function StaticExample()
        {
            var myExt:Extender = new Extender();
        }
    }
}

class Base {
    public static var test:String = "static";
}

class Extender extends Base
{
    public function Extender()
    {
        trace(test); // output: static
    }
    
}

インスタンスプロパティが、同じクラスまたはスーパークラス内で静的プロパティと同じ名前を使用するように定義されている場合、インスタンスプロパティはスコープチェーン内で優先順位が高くなります。インスタンスプロパティは、静的プロパティを「シャドウする」と言います。これは、静的プロパティの値ではなくインスタンスプロパティの値が使用されることを意味します。例えば、次のコードは、Extender クラスが test というインスタンス変数を定義すると、trace() ステートメントは、静的変数の値ではなくインスタンス変数の値を使用することを示します。

package
{
    import flash.display.MovieClip;
    public class StaticExample extends MovieClip
    {
        public function StaticExample()
        {
            var myExt:Extender = new Extender();
        }
    }
}

class Base
{
    public static var test:String = "static";
}

class Extender extends Base
{
    public var test:String = "instance";
    public function Extender()
    {
        trace(test); // output: instance
    }
    
}

 

このページに新しいコメントが追加された場合に、電子メールでの通知を希望する。 | コメントレポート