Reputation: 1944
Question: Am I right that the super()
constructor is called before the field initializations of my inherited class are done and by this the initializations can overwrite what I already initialized?
The title and maybe the question sound somewhat confusing, so I will try to clarify my question.
I have an abstract class Geometry
which has a protected abstract void
method.
This method is called in the constructor of the Geometry. I figured out that this call caused the problem I had.
In my extended class, ExtendedGeometry
I implemented the abstract method by calling a private method:
@Override
protected void createGeometry() {
loadModel();
}
The private void loadModel()
method filles a vertexList
and is done.
The vertexList
is defined as private ArrayList<Integer> vertexList = new ArrayList<Integer>();
.
When I now call update()
on my model, the vertexList appears to be empty. And even before that, although I initialized the variable directly as shown above, it appears to be null
in the loadModel()
method.
So I think my steps are:
ExtendedGeometry
.loadModel()
.So in step 4 I expected the variable to be not null and in step 7 to be filled.
To solve it I found three solutions:
loadModel()
in a constructor of my ExtendedGeometry
instead of calling it from the overriden createGeometry()
. init()
method for the Geometry
class, which then calls the createGeometry()
.So after trying out all this stuff I realized that the explanation seems to be that my superclass is able to work with the declaration but not the initialization of my subclass. This leads me to the conclusions that the steps done are:
ExtendedGeometry
.super()
constructor is called.ExtendedGeometry
get initialized. (What overrides the initialization done with super()
.)So my question is a simple yes/no question (which could be extended with explanations, if I'm wrong - or additions if I'm right):
Am I right that the super()
constructor is called before the field initializations of my inherited class are done and by this the initializations can overwrite what I already initialized?
I first thought this is a problem of visibility, but while tracking down the problem this seems to be the only solution I can come up with.
Just for completeness and maybe to better understand here is my 95 % reduced code, sorry it has no JavaDoc. But I added some comments to show the problem and explain.
The most important one, here is the ExtendedGeometry.java
:
package geometry;
import java.util.ArrayList;
public class ExtendedGeometry extends Geometry {
// PROBLEM 1: the ArrayList is already initialized here
private ArrayList<Integer> vertexList = new ArrayList<Integer>();
// usually this is Vector3f from lwjgl, but for
// STO I changed it to Integer
private void loadModel() {
// PROBLEM 2: but the ArrayList is null here!
System.out.println("Initializing vertexList which is " + vertexList);
// PROBLEM 3: leaving the following lines out
// does not change anything in the output
// of the update() method
if(vertexList == null)
vertexList = new ArrayList<Integer>();
// PROBLEM 4: filling the "newly" initialized vertexList,
// but not the old one
vertexList.add(1);
vertexList.add(2);
vertexList.add(3);
}
public void update() {
// PROBLEM 5: as you can see, you see nothing:
// the vertexList has no content
System.out.println("vertexList of size: " + vertexList.size());
for(Integer i : vertexList) {
System.out.print(i);
}
System.out.println();
}
/*// PROBLEM 6 / SOLUTION: If I leave out the loadModel in
// createGeometry() but use this constructor instead
// it works
public SpecializedGeometry() {
loadModel();
}
*/
@Override
protected void createGeometry() {
loadModel();
}
}
The Geometry.java
class, its super class:
package geometry;
public abstract class Geometry {
public Geometry() {
// every geometry has to be created
createGeometry();
}
/*// If I add an init method like this, it works
public void init() {
createGeometry();
// of course this line has to be removed
// from the constructor
}
*/
// this is the abstract method to create a geometry
protected abstract void createGeometry();
}
The Simulation.java
just demonstrates how my program is build in general:
package simulation;
import geometry.ExtendedGeometry;
public class Simulation {
private ExtendedGeometry geometry = null;
public Simulation() {
}
public boolean init() {
// initializes all simulation stuff,
// now only creates the geometry
geometry = new ExtendedGeometry();
// geometry.init(); // this is a possible fix, see Geometry.java
return true;
}
public void update() {
// does calculations and updates everything
// accordingly
if(geometry != null) {
geometry.update();
}
}
}
The MainWindow.java
, nothing too special here:
package main;
import simulation.Simulation;
public class MainWindow {
private Simulation simulation = null;
public boolean init() {
// create the simulation and initialize it
// usually here is a bunch of initializations
simulation = new Simulation();
return simulation.init();
}
public void run() {
// in this example I close after 10 loop runs,
// of course 1 would be sufficient as well
int x = 0;
// the main loop handles inputs, event manager,
// updates, drawing, ...
while(x++ < 10) {
// update simulation
simulation.update();
}
}
}
And finally the boring Main.java
:
package main;
public class Main {
public static void main(String[] args) {
MainWindow mw = new MainWindow();
if(mw.init()) { // init and
mw.run(); // run main loop
}
}
}
Upvotes: 2
Views: 1164
Reputation: 32959
I believe you have answered your own question that Yes, the extended class is fully initialized before the child class is initialized.
You have run into a basic rule of OOD, you should "never" call a non-static, non-final method from a constructor. If the constructor calls a method that can be overridden by a sub-class errors of this type are too common.
Upvotes: 1