繁体   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