Keep reference to new object passed into super con

2019-06-16 11:40发布

问题:

Is there a good way to maintain a reference to an object created in a constructor that needs to be passed to the super constructor of some extended class (other than making it accessible from the super class or passing it into the constructor as a parameter)?

Let me clarify with an example. Take this class (which I can't modify and which doesn't give me access to foo):

class TestA {
    TestA(Object foo) {}
}

Now, I would like to extends this class as follows:

class TestB extends TestA {
    Object myCopyOfFoo;

    TestB() {
        super(new Object());
    }
}

Is there a good way to store the created new Object() in myCopyOfFoo?

Neither one of these three ideas work:

TestB() {
    myCopyOfFoo = new Object();
    super(myCopyOfFoo);
}

(Error: Constructor call must be the first statement in a constructor)

TestB() {
    super(myCopyOfFoo = new Object());
}

(Error: Cannot refer to an instance field myCopyOfFoo while explicitly invoking a constructor)

TestB() {
    super(makeFoo());
}

Object makeFoo() {
    myCopyOfFoo = new Object();
    return myCopyOfFoo;
}

(Error: Cannot refer to an instance method while explicitly invoking a constructor)

I guess I could do the following, but it's neither thread-safe nor elegant:

static Object tempFoo;

TestB() {
    super(tempFoo = new Object());
    myCopyOfFoo = tempFoo;
}

Does anyone have a better idea for me? And why on earth are my first two ideas not legit?

回答1:

How about:

class TestB extends TestA {
    Object myCopyOfFoo;

    // I assume you actually wanted this to take a parameter called foo?
    // I've left it as per the question...
    TestB() {
        this(new Object());
    }

    private TestB(Object copy) {
        super(copy);
        myCopyOfFoo = copy;
    }
}

As the second constructor is private, it can only be called within the same class (or an enclosing class) so you just need to make sure that anything calling the second constructor has made an appropriate copy, as the first constructor does.

EDIT: If your real situation is that you're taking a copy of an existing parameter, then this would work...

class ClassB extends ClassA {
    private final Foo copyOfInput;

    ClassB(Foo input) {
        super(input = input.clone());
        copyOfInput = input;
    }
}

It's pretty ugly though :(



回答2:

Another option:

public class TestB extends TestA {

    Object myCopyOfFoo;

    private TestB(Object foo) {
        super(foo);
        myCopyOfFoo = foo;
    }

    public static TestB createInstance() {
        Object foo = new Object();
        return new TestB(foo);
    }

}


回答3:

What about the following:

class TestB extends TestA {
    Object myCopyOfFoo = new Object();

    TestB() {
        super(myCopyOfFoo);
    }
}

The object will only be initialised when creating a new object TestB, so in essence this will do what you want?