8.3コンストラクタは、順序を呼び出します

8.3.1シーケンスコンストラクタを呼び出して
、ビルド順に組み合わせ、継承、ポリモーフィズムの役割を示している、のは、以下の例を見てみましょう:
//:多型/ Sandwich..java
。//コンストラクタの順序コール
多型のためのパッケージ変更を。

class Meal {
    Meal() {System.out.println("Meal()");}
}
class Bread {
    Bread() {System.out.println("Bread()");}
}
class Cheese {
    Cheese() {System.out.println("Cheese()");}
}
class Lettuce {
    Lettuce() {System.out.println("Lettuce()");}
}
class Lunch extends Lettuce {
    Lunch() {System.out.println("Lunch()");}
}
class PortableLunch extends Lunch{
    PortableLunch() {System.out.println("PortableLunch()");}
}
public class Sandwich extends PortableLunch{
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Lettuce l = new Lettuce();
    public Sandwich(){
        System.out.println("Sandwich()");
    }
    public static void main(String[] args) {
        new Sandwich();
    }
}
/* Output
Lettuce()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()
 *///~

この例では、他のクラスは、複雑なクラスを作成し、各クラスは、コンストラクタの独自の宣言を有します。最も重要なクラスの一つは、3つの継承だけでなく、対象物の3人のメンバー(オブジェクトをも考慮すると、暗黙的にそれは、4である、継承)を反映サンドイッチ、です。サンドイッチのオブジェクトがメインで作成された場合()あなたは出力を見ることができます。また、これは、以下の遵守するためにコンストラクタを呼び出すために、この複雑なオブジェクトのシーケンスを示しています。

  1. 基底クラスのコンストラクタを呼び出します。このステップでは、再帰的に上に行くし続ける繰り返され、すべての最初は、派生クラスの一番下までなので、上のように次の層の派生クラスが続く階層のルート、およびを構築することです。
  2. 初期化方法は、宣言順のメンバーと呼ばれています。
  3. 主要な派生クラスのコンストラクタを呼び出します。

非常に重要であるためのコンストラクタを呼び出します。ときに継承、我々は、基底クラス、基底クラスのすべてを持っているし、publicおよびprotectedのメンバーとして任意の声明にアクセスできるようになるまで。これは、派生クラスで、基本クラスのすべてのメンバーが有効であることを前提としなければならないことを意味しています。標準的な方法は、コンストラクタの動作採取場所、オブジェクトのすべての部分のすべてのメンバーが得られる構築物です。しかし、コンストラクタの中、私たちは建物を終了した部材の使用を求めることを確認する必要があります。これを確実にするために、唯一の方法は、最初の基底クラスのコンストラクタを呼び出すことです。入るときに、派生クラスのコンストラクタシンクが初期化され、アクセス蓄積してきた私たちのメンバーでご利用いただけます。また、それは言うことです((例えば、B、CおよびLで栗のように)クラス内で定義されたオブジェクトのメンバーは、可能な限り、彼らは初期化されなければならないとき、あるため、コンストラクタのすべてのメンバーにも有効であることを知っています、クラスにオブジェクト)の方法を組み合わせることにより。このルールに従っている場合は、現在のオブジェクトのすべての基底クラスのメンバーとメンバーのオブジェクトが初期化されることを保証することができるようになります。残念ながら、このアプローチは、すべての場合には適用されません、あなたはBenpianの最後に表示されます。

8.3.2継承とクリーンアップの
時間は継承と方法を組み合わせて新しいクラスを作成するには、問題のオブジェクトをクリーンアップする心配はありません、子オブジェクトは、通常、処理のためにガベージコレクタに委ねられています。あなたがクリーンアップする問題が発生した場合は、新しいクラスの(名前から)慎重に処分()メソッドを作成する必要があります。我々は、特別なクリーンアップ操作の一部として他のリサイクルゴミを持っている場合と理由継承された日本酒の、派生クラス内にdispose()メソッドをカバーすることが必要です。継承したクラスを配置()メソッドをカバーするときは、処分の基底クラスバージョン()メソッドを呼び出すことを覚えておくようにしてください、それ以外の場合は、基底クラスのクリーンアップ操作は起こらなかっただろう。次の例は、この点を証明:
//:polymorphism/Frog.java
//クリーンアップと継承
ポリモーフィズムのためのパッケージ変更を。

class Characteristic {
    private String s;
    Characteristic(String s) {
        this.s = s;
        System.out.println("Creating Characteristic " + s);
    }
    protected void dispose() {
        System.out.println("disposing Characteristic " + s);
    }
}
class Description {
    private String s;
    Description(String s) {
        this.s = s;
        System.out.println("Creating Description " + s);
    }
    protected void dispose() {
        System.out.println("disposing Description " + s);
    }
}
class LivingCreature {
    private Characteristic p = new Characteristic("is alive");
    private Description t = new Description("Basic Living Creature");
    LivingCreature() {
        System.out.println("LivingCreature()");
    }
    protected void dispose() {
        System.out.println("LivingCreature dispose");
        t.dispose();
        p.dispose();
    }
}
class Animal extends LivingCreature {
    private Characteristic p = new Characteristic("has heart");
    private Description t = new Description("Animal not Vegetable");
    Animal(){System.out.println("Animal()");}
    protected void dispose() {
        System.out.println("Animal dispose");
        t.dispose();
        p.dispose();
        super.dispose();
    }
}
class Amphibian extends Animal {
    private Characteristic p = new Characteristic("can live in water");
    private Description t = new Description("Both water and land");
    Amphibian() {
        System.out.println(" Amphibian()");
    }
    protected void dispose() {
        System.out.println("Amphibian dispose");
        t.dispose();
        p.dispose();
        super.dispose();
    }
}
public class Frog extends Amphibian {
    private Characteristic p = new Characteristic("Croaks");
    private Description t = new Description("Eats Bugs");
    public Frog() {System.out.println("Frog()");}
    protected void dispose() {
        System.out.println("Frog dispose");
        t.dispose();
        p.dispose();
        super.dispose();
    }
    public static void main(String[] args) {
        Frog frog = new Frog();
        System.out.println("Bye!");
        frog.dispose();
    }
}
/*Output
Creating Characteristic is alive
Creating Description Basic Living Creature
LivingCreature()
Creating Characteristic has heart
Creating Description Animal not Vegetable
Animal()
Creating Characteristic can live in water
Creating Description Both water and land
 Amphibian()
Creating Characteristic Croaks
Creating Description Eats Bugs
Frog()
Bye!
Frog dispose
disposing Description Eats Bugs
disposing Characteristic Croaks
Amphibian dispose
disposing Description Both water and land
disposing Characteristic can live in water
Animal dispose
disposing Description Animal not Vegetable
disposing Characteristic has heart
LivingCreature dispose
disposing Description Basic Living Creature
disposing Characteristic is alive
 */

階層内の各クラスには、両方のタイプの特徴とメンバオブジェクトの説明が含まれ、そして、彼らは破壊されなければなりません。だから、コートの子オブジェクトが他のオブジェクトに依存すること、および初期化シーケンスは、逆の順序で破壊されなければなりません。(初期化フィールドが宣言の順序に従って行われるため)フィールドのために、それは生活の逆の順序を意味します。基底クラス(C ++でデストラクタの形態に従う)ためには、最初にその派生クラスに洗浄され、次いで、基本クラスべきです。派生クラスのクリーンアップは、基本クラスのいくつかのメソッドを呼び出すことができますので、これはですので、基本クラスのメンバーはまだ役割を果たしており、途中でそれらを破壊するべきではないことが必要です。カエルオブジェクトのすべての部分を見てからの出力が作成された破壊の逆の順序で行われています。

クリーンアップ作業を実行するために通常は必要ありませんが、私たちは、この例では見ることができますが、実行すると、あなたは慎重にと注意する必要があります。

コンストラクタ8.3.3動作内部のポリモーフィックメソッド
、コンストラクタ呼び出しの階層は興味深いジレンマが表示されます。内部ダイナミックな方法は、オブジェクトを構築してコンストラクタを呼び出すように結合した場合、何が起こるのでしょうか?

オブジェクトは、メソッド、またはそのクラスのクラスを派生し、そのクラスに属する知ることができないので、一般的なアプローチの中に、ランタイムコールでの結合の動的が、決定されます。

あなたがメソッドの定義を使用しますコンストラクタ、内部で動的にバインドメソッドを呼び出したい場合はカバーされています。オブジェクトが完全に構築される前に、オーバーライドされたメソッドが呼び出されますので、この呼び出しの結果は、予想するのは非常に難しいことができます。これは見つけるのは難しいいくつかの隠れたエラーが発生する場合があります。

概念的から、実際にオブジェクトを(これは簡単な作業ではありません)を作成するためにコンストラクタの作品です。任意のコンストラクタ内では、オブジェクト全体は部分的にしか形成することができる - 私たちは、基本クラスのオブジェクトが初期化されている知っています。構成は、オブジェクトの構築プロセスにおける唯一のステップで、オブジェクトのクラスに属し、このクラスのコンストラクターに由来する属している場合は、エクスポート部はまだ初期化されていないと呼ばれているこの時点で構成されています。しかし、動的にバインド呼び出しのための方法は、深いクラスのメソッドを呼び出すことができエクスポート継承階層に出欠落します。私たちは、コンストラクタ内そうになっている場合は、メソッドを呼ぶかもしれないが、このアプローチのメンバーを初期化するために操作されていない可能性があります - それは確かに災害につながります。

どこに問題がある。この例に従うことにより、我々は表示されます:
//:ポリモーフィズム/ PolyConstructors.java
//コンストラクタとポリモーフィズム
。//製品ドンの`tあなたが期待するかもしれないどのような
多型のためのパッケージ変更を。

class Glyph {
    void draw(){System.out.println("Glyph.draw()");}
    Glyph() {
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glyph after draw()");
    }
}
class RoundGlyph extends Glyph {
    private int radius = 1;
    RoundGlyph(int r) {
        radius = r;
        System.out.println("RoundGlyph.RoundGlyph().radius = " + radius);
    }
}
public class PolyConstructors {
    public static void main(String[] args) {
        new RoundGlyph(5);
    }
}
/*Output
Glyph() before draw()
Glyph.draw()
Glyph after draw()
RoundGlyph.RoundGlyph().radius = 5
 */

Glyph.draw()メソッドをカバーするように設計され、このカバーはRoundGlyphで所定の位置にあります。しかし、グリフのコンストラクタ呼び出し為替のこの方法は、結果は我々の目標のように見えるストリップ、と対RoundGlyph.draw()になります。しかし、あなたは出力を見れば、私たちは、グリフのコンストラクタ呼び出しは()メソッド、1のデフォルトの初期値よりも半径が、0を描くときには、画面上になることがあります点のみを描いた、またはすべてを行いいいえ、私たちは、絶望に見て、プログラムが動作しないことができる場所を見つけるためにしようとすることができます。

初期化シーケンスに関する資料の冒頭は非常に完全ではありませんが、公式の嘘、このパズルを解くための鍵。初期の実際のプロセスは以下のとおりです。

  1. 何かが起こる前に、ストレージスペースは、マスターズに初期化されたバイナリオブジェクトに割り当てられています。
  2. 上記基底クラスのコンストラクタを呼び出す場合。この場合には、ステップ1による被覆された後に延伸を呼び出す()メソッドは(コンストラクタRoundGlyph前に呼び出される)は、この時間はゼロ半径であることを見つけます。
  3. 初期化方法は、宣言の順序のメンバーと呼ばれています。
  4. 派生クラス本体のコンストラクタを呼び出します。

これは少しを持っており、それはただのゴミのために確保するのではなく、少なくともゼロ(値または「ゼロ」と値を持ついくつかの特殊なデータ型)に初​​期化すべてです。

したがって、コンストラクタを書き込む準有効面がある:「最も簡単な方法のものは、通常の状態にオブジェクトを作るために、可能であれば、他のメソッドを呼び出すことは避けてください。」唯一の安全な呼び出しが基本クラス最後のメソッドであるコンストラクタメソッドでは(もプライベートメソッドに適用され、彼らは自動的にfianl方法を所属します)。これらのメソッドはカバーできない、したがって、上記の問題は驚くべきことでは表示されません。あなたは、常にこのガイドラインに従うことができないかもしれませんが、努力は彼に向かってなされるべきです。

おすすめ

転載: www.cnblogs.com/cgy-home/p/11130246.html