[英]Java: When I Instantiate a Subclass of an Abstract Class It Doesn't Recognize the Constructor of its Superclass
我沒有太多的 Java 經驗,但我看到代碼中存在抽象 class 和某個構造函數,然后是該抽象 class 的子類而沒有構造函數。 然后當子類被實例化時,它會用它的超類構造函數來構造。 那正確嗎?
我有這個抽象的 class:
public abstract class Tile{
public int x;
public int y;
public int z;
protected Color color;
protected float friction;
protected float bounce;
protected boolean liquid;
public void Tile(int x, int y, int z){
this.x = x;
this.y = y;
this.z = z;
init();
}
abstract protected void init();
而這個子類:
public class TestTile extends Tile{
protected void init(){
color = Color.RED;
friction = 0.1f;
bounce = 0.2f;
liquid = false;
}
}
但是當我用這個實例化一個 TestTile 時:
Tile tile = new TestTile(0, 0, 0);
init() 方法永遠不會運行。 其中定義的所有值都是 null。 我嘗試在子類中創建一個我認為可能是冗余的構造函數,它只是使用完全相同的參數調用 super,但是當我這樣做時,即使 super(x, y, z) 是其中唯一的語句,它也會這樣說:
TestTile.java:27:對 super 的調用必須是構造函數中的第一條語句
我想做一堆 Tile 的子類來實現 Tile 的屬性。 如果這不是正確的方法,那么更好的方法是什么?
如果與任何事情有關,我正在使用 32 位 Ubuntu Linux 11.04。
謝謝。
您的構造函數不是屬性構造函數格式,它是void
,使它:
public Tile(int x, int y, int z){
this.x = x;
this.y = y;
this.z = z;
init();
}
我沒有看到需要三個 arguments 的 TestTime 構造函數。 我根本看不到任何 ctor,這意味着您所擁有的只是編譯器為您提供的默認值。 我是不是 go 太快而錯過了它?
我建議要特別注意這一點。 我會重新考慮這個設計:
試試這個 - 它包括對您的構造函數的修復,並避免其他線程指出的問題:
public abstract class Tile{
public int x;
public int y;
public int z;
protected Color color;
protected float friction;
protected float bounce;
protected boolean liquid;
public Tile(int x, int y, int z){
this.x = x;
this.y = y;
this.z = z;
}
}
public class TestTile extends Tile{
// You're missing this.
public TestTile(int x, int y, int z)
{
super(x, y, z);
this.init();
}
protected void init(){
color = Color.RED;
friction = 0.1f;
bounce = 0.2f;
liquid = false;
}
}
首先, Tile
只有一個帶x、y、z參數的構造函數,沒有默認構造函數,所以你必須在TestTile
構造函數中調用super(x, y, z)。 正如slandau所說,“構造函數”的返回類型void
。
TestTile
需要聲明參數或傳遞默認值:
public TestTile(int x, int y, int z) {
super(x, y, z);
}
public TestTile() {
super(0, 0, 0);
}
在 Java 中,在構造函數中調用抽象方法的風險很多,參見此處,實例未正確初始化。 您只能安全地調用 static 方法(此處不起作用)。
public TestTile(int x, int y, int z) {
super(x, y, z);
color = Color.RED;
friction = 0.1f;
bounce = 0.2f;
liquid = false;
}
或者您需要在派生的 class 中調用私有方法(從Tile
中刪除抽象init()
):
public TestTile(int x, int y, int z) {
super(x, y, z);
init();
}
private void init() {
color = Color.RED;
friction = 0.1f;
bounce = 0.2f;
liquid = false;
}
你確定成員在這里是正確的實施嗎? 也許抽象方法(getter)在這里聲明一個行為並在子類中實現它可能會更好?
public abstract class Tile {
public int x;
public int y;
public int z;
public Tile(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public abstract Color getColor();
public abstract float getFriction();
public abstract float getBounce();
public abstract boolean isLiquid();
}
public class TestTile extends Tile {
public TestTile(int x, int y, int z) {
super(x, y, z);
}
public Color getColor() {
return Color.RED;
}
public float getFriction() {
return 0.1f;
}
public float getBounce() {
return 0.2f;
}
public boolean isLiquid() {
return false;
}
}
構造函數不是繼承的,所以在創建TestTile object時不會調用Tile的三參數構造函數。 您需要從 TestTile 構造函數中顯式調用三參數 Tile 構造函數,就像您說的那樣,但是對 super(x,x,x) 的調用必須是 TestTile 構造函數的第一條語句。
就像 Matt Ball 所說的那樣,在您刪除 void 返回類型之前,您的 Tile “構造函數”並不是真正的構造函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.