Question

There are two classes: A and B. B is the subclass of A. A stores a reference of B, which may in certain scenarios a reference to this as well.

public B b;

In the constructor of A, is it legal to cast the this reference to B (provided that I know that the concrete type of the object under construction is B)? (Syntactically, I know it is; design-wise, it probably reflects a bad component design; but I want to know if it has any severe risks and thus unacceptable.)

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

The question has arisen because by this time, the constructor of B has not yet completed (because this runs exactly when B calls super).

I know that accesssing b before its constructor completes means that I'm accessing (semantically) uninitialized members (so I never do that), but is this all?

Était-ce utile?

La solution

- Well the problem will arise if there is any other class that also extends to A, then it may be casted by default to Class B.

- I would advice you to use instanceof to sort this thing out....

Autres conseils

This constellation does not break any other rules besides good OO design. Java is prepared for this case, because all fields of B get initialized even before any of the constructors get invoked, as shown by the following example:

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);
    }
}

This outputs:

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

That means that in A(), B's member variables are simply in the same state as A's member variables before they get set. Both have been initialized to their defaults (0 for int, false for boolean, null for objects, ...) and can be used. A strong pitfall is that B's member variables can be set in A(), but can be overwritten by B's own constructor, which is very counterintuitive.

I like this question because it is expressed simply and clearly, yet it raises more complicated questions, which reach into other topics like compiler internals and details in object creation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top