簡體   English   中英

Java - 在子類中初始化超類變量?

[英]Java — Initializing superclass variables in subclasses?

好的,例如,假設我有一個名為“Vehicle”的抽象類。 除了其他方面,Vehicle類還有一個名為wheels的靜態變量,它沒有被初始化。 我想要做的是從Vehicle類擴展其他子類,如“Motorcycle”和“Truck”,並在這些子類中初始化輪子。

碼:

public abstract class Vehicle {
    static int wheels; //number of wheels on the vehicle
}

但以下不起作用:

public class Motorcycle extends Vehicle {
    wheels = 2;
}

有沒有辦法有效地做到這一點?

編輯:感謝所有回復的人。 我認為制作實例可能是一種更好的方法,而不是將它們全部放在不同的類中,但我沒有完全得到java的“靜態”部分,所以我需要一些幫助。

我正在嘗試為我的程序做的是為摩托車和卡車類提供單獨的精靈,我希望它們是靜態的,這樣我每次創建摩托車或卡車的實例時都不必重新加載圖像。 除此之外,它們將具有幾乎相同的屬性,這就是為什么它們都將從Vehicle超類擴展。

我可以看到這樣做的唯一另一種方法是不在Vehicle類中聲明sprite變量,而是在Motorcycle / Truck類中,如下所示:

public abstract class Vehicle {
//Other coding
}

public class Motorcycle extends Vehicle {
static BufferedImage sprite = //initialize image
//Other coding
}

public class Truck extends Vehicle {
static BufferedImage sprite = //initialize image
//Other coding
}

如果“車輪”是靜止的,則只有一個,它將同時適用於所有車輛。 因此,三輪車,摩托車,18輪卡車和福特都將擁有相同數量的車輪。

這對我來說沒有意義。 最好讓'wheels'成為父類中的實例變量,但每個子類都適當設置。

但你可以試試

Vehicle.wheels = 2;

注意:自從您添加到問題中后,我正在添加我的答案。

我喜歡你在每個子類中都有靜態的想法。 但你應該把它們變成私人的。 然后把一個抽象方法放在父類(Vehicle)中

public abstract BufferedImage getSprite();

然后每個直接子類必須具有相同的方法,並且它可以返回私有靜態變量。

使變量保持靜態,因此您只需加載一次。 將它們設為私有,以便類本身之外的代碼不會愚弄它並引入錯誤。 如果可能的話,你可以讓它們成為'final',這樣類中的代碼就不能在事后改變它並引入bug。 (一個'最終'變量不能改變它的值,但它的值的內容可能會改變。所以'最終'不是很好,因為它可能。)

你要做的事情從根本上是有缺陷的。 可以Motorcycle初始化一次wheels

// Static initializer
static
{
    wheels = 2;
}

...或每次創建實例時:

// Instance initializer
{
    wheels = 2;
}

但是只有一個變量 - 不是Motorcycle 一個變量Truck等的變量 。如果你對TruckMotorcycle做同樣的事情,那么最后初始化的那個將“贏”。

目前尚不清楚你想如何使用這個字段 - 但是如果你只有一個靜態字段,那么它只會有一個值 - 而不是每個子類一個。

靜態成員只定義一次,並且對於每個擴展類都是通用的。 更改其中一個中的值將影響所有其他值。 這就是我相信你真正想要實現的目標:

public abstract class Vehicle {
    private int _wheels; //number of wheels on the vehicle
    public int getWheels(){return _wheels;}

    protected Vehicle(int wheels){
        _wheels = wheels;
    }
}

public class Motorcycle extends Vehicle {
    public Motorcycle(){
        super(2);
    }
}

public class Car extends Vehicle {
    public Car(){
        super(4);
    }
}

我認為有一個更優雅的方式來做到這一點

我要提議的內容仍然受到您需要實例的限制。 我沒有看到任何解決方法,因為你希望wheels作為超類的一部分暴露,但wheels的值依賴於子類和Vehicle內部沒有沒有實例的子類類型的概念。

在我看來,在這種情況下,“輪子”既不是靜態的也不是非靜態的。 它是類元數據 指定類元數據的Java方法是通過注釋。

你需要的是一個用戶定義的注釋,如下所示:

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface VehicleMetadata{
    int wheels();
}

然后,您按如下方式注釋Motorcyle:

@VehicleMetadata(2)
public class Motorcycle extends Vehicle {}

在超類中,您提供了一個獲取annotation屬性值的訪問器。 我建議你使用“懶惰評估”方法,這樣每次需要時都不會使用反射。

注意使用this來獲取實例:

private String wheelsValue;

public String getWheels() {
    if (this.wheelsValue== null) {

        VehicleMetadatane = null;
        for (Annotation annotation : this.getClass().getAnnotations()) {
            if (annotation instanceof VehicleMetadata) {
                ne = (VehicleMetadata) annotation;
                break;
            }
        }

        wheelsValue = ne.wheels();
    }
    return wheelsValue ;
}

在我看來,這是最優雅的解決方案。

原始類聲明:

public abstract class Vehicle {
    static int wheels; //number of wheels on the vehicle
}

public class Motorcycle extends Vehicle{...}
public class Truck extends Vehicle{...}

不起作用,因為靜態變量與聲明它的類一起使用。靜態類變量僅為每個類的一個變量實例創建內存存儲,而不是每個類對象。 當編譯器(jvm)在類Vehicle中看到靜態變量時,它會將內存分配給該變量,並且該內存位置是靜態的(不會更改)。 Vehicle類的每次后續使用,無論是擴展還是實例化為對象,都將指向靜態變量的內存中的相同位置。

為了在子類中使用靜態變量,您必須在方法中使用它。 所以,你本質上可以像這樣重寫你的摩托車類:

class Motorcycle extends Vehicle{
    public Motorcycle(){
        wheels = 2;
    }
}

它會編譯; 但是,您可能無法獲得預期的結果。 例如,如果您在代碼中執行此操作(假設Truck類被聲明為Motorcycle類並將4分配給wheel並且有一個getter方法來返回wheel的值)。

Motorcycle cycle = new Motorcycle();
Truck pickup = new Truck();
...
System.out.println("Motorcycle has " + cycle.getWheels() + " wheels.");

將打印:

摩托車有4個輪子。

也許你想考慮一下你正在使用的構造函數。

public Vehicle(int wheels) {
    this.wheels = wheels; 
}

public Motorcycle(int wheels) {
    super(wheels);
}

public Motorcycle cycle = new Motorcycle(2);

Motorcycle使用知道如何處理參數的超級構造函數。 它會自動將車輪設置為2。

如果在對象中創建一個靜態變量,那么對於您將要創建的每個Vehicle類,它都是相同的,即使您要為抽象Vehicle類創建另一個子類。 這是因為任何靜態變量的“性質”。

我想你想使用一個非靜態變量,這樣對於抽象Vehicle類的任何子類的每個實例,你都可以確定輪子的值,並按如下方式完成:

public abstract class Vehicle {
    public int wheels; //number of wheels on the vehicle
}

和任何子類:

public foo extends Vehicle{

     public void someMethode(){
         this.wheels = 2;
     }
}

您也可以為靜態變量執行此操作,但隨后您將為Vehicle的任何子類的每個實例更改它

希望我能幫助你

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM