問題:在我的繼承類的字段初始化完成之前調用super()
構造函數並且由此初始化可以覆蓋我已經初始化的內容嗎?使用繼承類和超類初始化的順序
標題,也許問題聽起來有些混亂,所以我會盡力澄清我的問題。
我有一個abstract class Geometry
它有一個protected abstract void
方法。 在Geometry的構造函數中調用此方法。我發現這個電話造成了我的問題。
在我的擴展類,ExtendedGeometry
我通過調用私有方法實現的抽象方法:
@Override
protected void createGeometry() {
loadModel();
}
的private void loadModel()
方法FILLES一個vertexList
和完成。
vertexList
定義爲private ArrayList<Integer> vertexList = new ArrayList<Integer>();
。
當我在我的模型上調用update()
時,vertexList看起來是空的。甚至在此之前,儘管我如上所示直接初始化變量,但在loadModel()
方法中似乎是null
。
所以我覺得我的步驟是:
- 我打電話的
ExtendedGeometry
(隱含的)構造函數。 - 我隱式地初始化一個私有成員變量。
- 超級構造函數調用我的overriden方法,調用
loadModel()
。 - - >奇怪:成員變量現在爲空,但聲明!
- 我再次初始化成員變量。
- 我用值填充它。
- 在主循環中,我打印變量的內容,但它是空的。
因此,在第4步,我預計該變量不爲空,並在步驟7中填充。
爲了解決它,我發現了三個解決方案:
- 第一種方案是在我
ExtendedGeometry
的構造函數調用loadModel()
而不是從重寫createGeometry()
調用它。 - 第二種解決方案是簡單地爲
Geometry
類引入init()
方法,然後調用createGeometry()
。 - 第三種解決方案是隻聲明成員變量,但不初始化它。
所以嘗試了所有這些東西后,我意識到的解釋似乎是,我的超能與聲明但不是初始化我的子類的工作。 這使我得出的結論是,完成的步驟是:
- 聲明被提升。 (在編譯期間)
- 我調用
ExtendedGeometry
的(隱式)構造函數。 - 調用構造函數
super()
。 ExtendedGeometry
的成員被初始化。 (什麼會無視super()
進行初始化。)
所以我的問題是一個簡單的是/否的問題(這可能與解釋延長,如果我錯了 - 或補充,如果我是正確的):
我說的super()
構造函數在我的繼承類的字段初始化完成之前被調用,通過這個初始化可以覆蓋我已經初始化的東西嗎?
我首先想到這是一個可見性問題,但在追蹤問題時,這似乎是我能想到的唯一解決方案。
只是爲了完整,也許在這裏更好地理解我的代碼減少了95%,抱歉它沒有JavaDoc。但我添加了一些評論來顯示問題並解釋。
最重要的一個,這裏是ExtendedGeometry.java
: 封裝幾何;
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();
}
}
的Geometry.java
類,其超類:
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();
}
的Simulation.java
只是表明我的程序是如何打造一般:這裏
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();
}
}
}
的MainWindow.java
,沒有什麼太特別的:
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();
}
}
}
最後無聊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
}
}
}
感謝您的額外解釋,我從來沒有聽說過這個基本規則。我經常使用它,因爲我看到並使用了構造器+初始化器原則。很好知道! –