Constructors and Super
I wrote a class and a subclass - both immutable.
The superclass only has one constructor and the subclass
also has one constructor (though it is different than the
superclass).
I need for the subclass constructor to take some
numbers, perform some operations and call the the
constructor of the superclass.
Of course this wont work because super() has to be the first call.
Also, this subclass should only have this ONE constructor.
How should i resolve this problem?
These are all the options I can see:
- Dont make the classes immutable
That seems drastic.
- Add the subclasses constructor to the superclass
Moving behavior to an unrelated class seems bad.
- Using a static method that creates the object
Seems like my only real option but then how do i stop people
from instantiating the class (using the superclass' constructor)?
> - Using a static method that creates the object
> Seems like my only real option
Based on:
"I need for the subclass constructor to take some
numbers, perform some operations and call the the
constructor of the superclass."
I would agree.
>but then how do i stop
> people
> from instantiating the class (using the superclass'
> constructor)?
Maybe make the superclass constructor protected?
> - Using a static method that creates the object> Seems like my only real option but then how do i stop> people> from instantiating the class (using the superclass'> constructor)?Make the superclass constructor package private.
> Of course this wont work because super() has to be the first call.
Disregarding the design implications, you can get around this in a semi-sneaky manner:
class Foo {
private int i;
Foo(int i) {
this.i = i;
}
}
class Bar extends Foo {
Bar(int x, int y) {
super(someComplexCalculations(x, y)); // < aha.
}
private static int someComplexCalculations(int x, int y) {
// ...
return 0;
}
}
~
@Op. What type of calculations? Are they advanced? Can't they be made in the call to super?
Thanks for all your ideas and help.
> super(someComplexCalculations(x, y)); // < aha.
Haha. If that works that is awesome.
The calculations are simple and couldve have actually been
done within the super( calc, calc ) call except for a necessary
b@stard if statement that ruins the whole thing, lol.
if(boolean){
super(regular);
} else {
super( calculations );
}
Im ok with a factory design (thats what it is right?) and making a
static creator and making the super constructor private.
This is making my first forray into immutability unpleasant.
I was already warned not to get "creative" with this design, lol.
> Haha. If that works that is awesome.I wouldn't post it if it didn't... ;o)~
> if(boolean){> super(regular);> } else {> super( calculations );> }This does also worksuper(boolean ? regular : calculations);
super(boolean ? regular : calculations);
That would be acceptable except the super constructor is
(float, float). I could add a constructor that takes an array
but is there a way guarentee an array size in a constructor or
method?
As in:
some Method(array[of only size 2]){ }
Maybe have the constructor throw an error if the array size is of?
It's kinda hack-ish, but I would use a simple struct type of class long before I ever used an array:
class ParamSet {
public float width = 0;
public float height = 0;
}
class A {
private A(float area) {
this.area = area;
}
}
class B {
public B(ParamSet params) {
super(computeArea(params));
}
private static float computeArea(ParamSet params) {
return (params.width * params.length);
}
}
There's really no reason to group the width and length like this, so this analogy is a terrible example.
Message was edited by:
kevjava (he did say floats)
Haha, thats funny because the subclass in my example isactually the sub of a struct class, lol.So i couldnt have a struct class to hold the couple values thesuperclass exists to hold. Youre right though, in other situations that would be better.
How would I chain classes that only had a static method to
instantiate them?
public Class1{
private Class1(...){}
static Class1 create(...){}
}
public Class2 extends Class1{
private Class2(...){}
static Class2 create(...){}
}
It seems that this wouldnt be possible. Class1 is unsubclassable
right? Protected allows access from anywhere in the package and
that is way too much access.
> Protected allows access from anywhere in the package and
> that is way too much access.
Perhaps inheritance is not a good design decision in your case; it sounds like composition may be a better choice. If your class actually needs to be extended, you should design it to do so. Otherwise, prevent it.
Anyway, what risk do you perceive in having package access to the superclass constructor?
~
> Anyway, what risk do you perceive in having package access to the superclass constructor?
I cant use composition though that was a good idea previously
brought up.
Im still trying to fix this super() problem.
class BaseClass{
// Immutable
public BaseClass(val1, val2){}
}
// This is not possible
class SubClass1 extends BaseClass{
public SubClass1(val1, val2, val3){
// calculations
super(val1, val2);
}
}
// So if this...
class SubClass1 extends BaseClass{
private SubClass1(val1, val2){
super(val1, val2);
}
public static SubClass1 create(val1, val2, val3){
// calculation
return new SubClass1(val1, val2);
}
}
// Now cant do this
class SubClass2 extends SubClass1{
// F'd real good
}
> I cant use composition...
I don't believe that. Why can't you use composition? Why do you think you need to extend the immutable class?
Until you provide some substantial justification or a reasonable context around the problem, you're not likely to get much in the way of useful help. Rather, you're likely to get responses like mine; i.e., your design is wrong. As mentioned before, either design for inheritance or prevent it. Either your "immutable" superclass should be designed to be extended, or you should forget about inheritance (what extended functionality is the subclass offering, anyway?) and simply construct an appropriate instance of the superclass based on some condition.
You may also want to see reply #3 again, but I still question the need for your proposed design.
~
The 3 classes have to be interchangable in the code.
I suppose I could create an interface to make them all
interchangable.
But now im making an interface and creating twice as many objects
(for every composed class i know am instantiating that class and the
reference to other classes).
It doesnt seem elegant (not that ive found anything elegant) for
3 classes that are conceptual extensions of each other.
All i want to do is make one calculation before the call to super(...), lol,
and there wouldnt be any need for all this.
Im just going to add the one calculation to the superclass.
Its not worth all this for one if statement and a single calculation.
> The 3 classes have to be interchangable in the code.
Why? Why do you need three classes?
> I suppose I could create an interface to make them
> all interchangable.
I don't see why you would choose that route, either.
> But now im making an interface and creating twice as many objects
> (for every composed class i know am instantiating that class and the
> reference to other classes).
> It doesnt seem elegant (not that ive found anything elegant) for
> 3 classes that are conceptual extensions of each other.
It doesn't sound elegant to me, either. But I think that's because you're approaching your design from a single point of view, and you haven't provided any context from which others with perhaps more experience may make a recommendation for a design that actually *is* elegant.
> All i want to do is make one calculation before the
> call to super(...), lol,
See reply #3.
> and there wouldnt be any need for all this.
There has been no evidence that you need any of "this" anyway... :o)
Unfortunately, without any reasonable context, there's not much else I'm able to help with. Best of luck!
~
Thank god for the ternary operator. I was able to make a very ugly:super( bool ? val1 : calculation(), bool ? val1 : calculation() ..... );Now everything can be public, no statics, no factorys, no problems.
> Thank god for the ternary operator. I was able to> make a very ugly:If that's your preference... *shrugs*~
> All i want to do is make one calculation before the
> call to super(...), lol,
> See reply #3.
Yea I hit a nonexistent roadblock when I first read that.
I was trying to do the whole thing in one method call - and therefore
needing an array but I didnt want to create a constructor that
took an array. Never once did it occur to me to call the method
X number of times. Which is essentially what the ternary is doing -
in fact ill probably replace it with a method.
Out of curiosity, why haven't you answered any of my questions? I didn't intend them to be interpreted rhetorically.
- What risk do you perceive in having package access to the superclass constructor?
- Why can't you use composition?
- Why do you think you need to extend the immutable class?
- What extended functionality is the subclass offering?
- Why do you need three [interchangeable] classes?
~
> Out of curiosity, why haven't you answered any of my questions? I didn't intend them to be interpreted rhetorically.
Easy Killer. I didnt intentionally not answer your questions. I thought
I had in part answered most.
- What risk do you perceive in having package access to the superclass constructor?
I really disliked the whole private constructors with static initializer
solution and was trying to find a solution without doing that. The
package access question is only relevant if im using that solution
which is why I didnt dwell on this. I didnt want the risk of other
programmers creating classes in this package that could break
the immutability of the 3 classes or getting around the factory setup.
- Why can't you use composition?
Because the 3 classes should be interchangeable. See below.
Like I said I could still use composition if the 3 classes implemented a
common interface.
1- Why do you think you need to extend the immutable class?
2- What extended functionality is the subclass offering?
3- Why do you need three [interchangeable] classes?
The base immutable class is a data struct that holds some values (just a few results from computations). These values should never be changed. I am writing a library that does computations on the values
in this class.
1 subclass holds additional computed information (about twice as much) that is sometimes needed. Now these lengthy computations
dont have to be recalculated every time theyre needed.
As there are thousands of these objects it is needless in many cases
to have this information stored in the base class.
The 2nd subclass isnt really as important and is actually a special case
of the 1st subclass which guarentees a certain state - the values
are in a certain useful set.
The library performs using the values in the base class.
It would be wasteful to write every computation for a case of each class.
