2

2つのクラスがあります:ABBのサブクラスですAAの参照を格納しますB。これは、特定のシナリオでは、への参照も格納する場合がthisあります。

public B b;

のコンストラクターで、への参照Aをキャストすることは合法ですか(構築中のオブジェクトの具体的なタイプがであることがわかっている場合?(構文的には、それが正しいことはわかっています。設計的には、コンポーネントの設計が悪いことを反映している可能性がありますが、重大なリスクがあり、許容できないかどうかを知りたいです。)thisBB

public A(...parameters) {
    b = (B) this;
}

この時点で、のコンストラクターはBまだ完了していないため、問題が発生しました(これは、B呼び出し時に正確に実行されるためsuper)。

bコンストラクターが完了する前にアクセスするということは、(意味的に)初期化されていないメンバーにアクセスしていることを意味することを知っています(したがって、決してそうしません)が、これですべてですか?

4

2 に答える 2

1

- A にも拡張される他のクラスがある場合、問題が発生し、デフォルトでクラス B にキャストされる可能性があります。

-instanceofこのことを整理するために使用することをお勧めします....

于 2013-01-08T10:56:33.663 に答える
1

このコンスタレーションは、優れた OO 設計以外のルールに違反するものではありません。次の例に示すように、コンストラクターが呼び出される前に B のすべてのフィールドが初期化されるため、Java はこの場合に備えています。

public class A {

    int aMember;

    public static final void main(String[] args) {
        new B();
    }

    A() {
        B b = (B) this;

        System.out.println("in A(), before b.bMember    has been set here, b.bMember    = " + b.bMember);
        System.out.println("in A(), before this.aMember has been set here, this.aMember = " + this.aMember);

        this.aMember = 5;
        b.bMember = 1; // will be overwritten in B()

        System.out.println("in A(), after  b.bMember    has been set here, b.bMember    = " + b.bMember);
        System.out.println("in A(), after  this.aMember has been set here, this.aMember = " + this.aMember);
    }
}

--

public class B extends A {

    int bMember;

    B() {
        super(); // invokes A()

        System.out.println("in B(), before this.bMember has been set here, this.bMember = " + this.bMember);

        this.bMember = 6;

        System.out.println("in B(), after  this.bMember has been set here, this.bMember = " + this.bMember);
    }
}

これは以下を出力します:

in A(), before b.bMember    has been set here, b.bMember    = 0
in A(), before this.aMember has been set here, this.aMember = 0
in A(), after  b.bMember    has been set here, b.bMember    = 1
in A(), after  this.aMember has been set here, this.aMember = 5
in B(), before this.bMember has been set here, this.bMember = 1
in B(), after  this.bMember has been set here, this.bMember = 6

つまり、A() では、B のメンバー変数は、設定される前は A のメンバー変数と同じ状態にあるだけです。どちらもデフォルト (int の場合は 0、ブール値の場合は false、オブジェクトの場合は null など) に初期化されており、使用できます。重大な落とし穴は、B のメンバー変数を A() で設定できるが、B 自身のコンストラクターによって上書きできることです。これは非常に直感に反します。

シンプルかつ明確に表現されているため、私はこの質問が好きですが、コンパイラの内部やオブジェクト作成の詳細など、他のトピックにまで及ぶ、より複雑な質問を提起します。

于 2013-01-08T11:50:07.593 に答える