简体   繁体   English

Java - 在子类中初始化超类变量?

[英]Java — Initializing superclass variables in subclasses?

Okay, so, for example, let's say I have an abstract class called "Vehicle". 好的,例如,假设我有一个名为“Vehicle”的抽象类。 The Vehicle class, has, among other things, a static variable called wheels, which is not initialized. 除了其他方面,Vehicle类还有一个名为wheels的静态变量,它没有被初始化。 What I want to do is have other subclasses extending from the Vehicle class, like "Motorcycle", and "Truck", and in these subclasses, have the wheels initialized. 我想要做的是从Vehicle类扩展其他子类,如“Motorcycle”和“Truck”,并在这些子类中初始化轮子。

Code: 码:

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

But the below doesn't work: 但以下不起作用:

public class Motorcycle extends Vehicle {
    wheels = 2;
}

Is there a way to do this effectively? 有没有办法有效地做到这一点?

EDIT: Thank you to all the people who replied so far. 编辑:感谢所有回复的人。 I get that making instances is probably a better way to go than to put them all in separate classes, but I don't get the "static" part of java perfectly, so I need a little help here. 我认为制作实例可能是一种更好的方法,而不是将它们全部放在不同的类中,但我没有完全得到java的“静态”部分,所以我需要一些帮助。

What I'm trying to do for my program is have separate sprites for the Motorcycle and Truck classes, and I want them to be static so that I won't have to reload the image every time I create an instance of a Motorcycle or Truck. 我正在尝试为我的程序做的是为摩托车和卡车类提供单独的精灵,我希望它们是静态的,这样我每次创建摩托车或卡车的实例时都不必重新加载图像。 Other than that, though, they'll have almost identical properties to each other, which is why they'll both be extending from the Vehicle superclass. 除此之外,它们将具有几乎相同的属性,这就是为什么它们都将从Vehicle超类扩展。

The only other way I can see this being done is by just not declaring the sprite variable at the Vehicle class, but at the Motorcycle/Truck class, like below: 我可以看到这样做的唯一另一种方法是不在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
}

If 'wheels' is static, there is only one and it will apply to all vehicles at the same time. 如果“车轮”是静止的,则只有一个,它将同时适用于所有车辆。 So tricycle, a motorcycle, an 18-wheeler truck and a Ford will all have the same number of wheels. 因此,三轮车,摩托车,18轮卡车和福特都将拥有相同数量的车轮。

That doesn't make sense to me. 这对我来说没有意义。 It would be better to have 'wheels' be an instance variable that is in the parent class but each subclass sets appropriately. 最好让'wheels'成为父类中的实例变量,但每个子类都适当设置。

But you can try 但你可以试试

Vehicle.wheels = 2;

NOTE: I'm adding to my answer since you added to your question. 注意:自从您添加到问题中后,我正在添加我的答案。

I like your idea of having statics in each of the subclasses. 我喜欢你在每个子类中都有静态的想法。 But you should make them private. 但你应该把它们变成私人的。 Then put an abstract method in the parent class (Vehicle) like 然后把一个抽象方法放在父类(Vehicle)中

public abstract BufferedImage getSprite();

Then each direct subclass has to have the same method and it can return the private static variable. 然后每个直接子类必须具有相同的方法,并且它可以返回私有静态变量。

Make the variable static so you only have to load them once. 使变量保持静态,因此您只需加载一次。 Make them private so that code outside the class itself can't fool with it and introduce bugs. 将它们设为私有,以便类本身之外的代码不会愚弄它并引入错误。 You could make them 'final' if possible so the code in the class itself can't change it after the fact and introduce bugs. 如果可能的话,你可以让它们成为'final',这样类中的代码就不能在事后改变它并引入bug。 (A 'final' variable can't have its value changed but the contents of its value can change. So 'final' isn't a wonderful as it could be.) (一个'最终'变量不能改变它的值,但它的值的内容可能会改变。所以'最终'不是很好,因为它可能。)

What you're trying to do is fundamentally flawed. 你要做的事情从根本上是有缺陷的。 You could make Motorcycle initialize wheels once: 可以Motorcycle初始化一次wheels

// Static initializer
static
{
    wheels = 2;
}

... or each time an instance was created: ...或每次创建实例时:

// Instance initializer
{
    wheels = 2;
}

But there's just one variable - not one for Motorcycle , one for Truck etc. If you did the same thing for both Truck and Motorcycle , then whichever is initialized last would "win". 但是只有一个变量 - 不是Motorcycle 一个变量Truck等的变量 。如果你对TruckMotorcycle做同样的事情,那么最后初始化的那个将“赢”。

It's not clear how you want to use this field anyway - but if you just have a single static field, then that's just going to have a single value - not one per subclass. 目前尚不清楚你想如何使用这个字段 - 但是如果你只有一个静态字段,那么它只会有一个值 - 而不是每个子类一个。

Static members are only defined once and are common to every extending class. 静态成员只定义一次,并且对于每个扩展类都是通用的。 Changing the value in one of them will affect all of the others. 更改其中一个中的值将影响所有其他值。 This is what I believe you really want to achieve: 这就是我相信你真正想要实现的目标:

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);
    }
}

I think there's a significantly more elegant way to do this 我认为有一个更优雅的方式来做到这一点

What I am about to propose still suffers from the limitation that you need an instance. 我要提议的内容仍然受到您需要实例的限制。 I don't see any way around that because you want wheels to be exposed as part of the superclass, but the value of wheels is dependent on the subclass and inside of Vehicle there is no notion of a subclass type without an instance. 我没有看到任何解决方法,因为你希望wheels作为超类的一部分暴露,但wheels的值依赖于子类和Vehicle内部没有没有实例的子类类型的概念。

In my opinion, 'wheels'in this case is neither a static or non-static property. 在我看来,在这种情况下,“轮子”既不是静态的也不是非静态的。 It is class metadata . 它是类元数据 And the Java way to specify class metadata is via annotations. 指定类元数据的Java方法是通过注释。

What you need is a user-defined annotation like this: 你需要的是一个用户定义的注释,如下所示:

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

You then annotate Motorcyle as follows: 然后,您按如下方式注释Motorcyle:

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

In the superclass you provide an accessor that gets the value of the annotation property. 在超类中,您提供了一个获取annotation属性值的访问器。 I would recommend you use a "lazy evaluation" approach so you don't use reflection every time you need the value. 我建议你使用“懒惰评估”方法,这样每次需要时都不会使用反射。

Note the use of this to get the instance: 注意使用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 ;
}

In my opinion, this is the most elegant solution. 在我看来,这是最优雅的解决方案。

The original class declaration: 原始类声明:

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

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

does not work because the static variable goes with the class it was declared in. Static class variables create memory storage for only one instance of the variable per class and not per class object. 不起作用,因为静态变量与声明它的类一起使用。静态类变量仅为每个类的一个变量实例创建内存存储,而不是每个类对象。 When the compiler (jvm) sees the static variable in the class Vehicle it allocates memory to that variable and that memory location is static (does not change). 当编译器(jvm)在类Vehicle中看到静态变量时,它会将内存分配给该变量,并且该内存位置是静态的(不会更改)。 Each subsequent use of the Vehicle class whether it is extended or instantiated as an object will point to the same location in memory for the static variable. Vehicle类的每次后续使用,无论是扩展还是实例化为对象,都将指向静态变量的内存中的相同位置。

In order to use the static variable in the child classes you have to use it inside a method. 为了在子类中使用静态变量,您必须在方法中使用它。 So, you could in essence re-write your Motorcycle class like this: 所以,你本质上可以像这样重写你的摩托车类:

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

and it will compile; 它会编译; however, you will may not get the results you expect. 但是,您可能无法获得预期的结果。 For example if you do this in your code (assuming Truck class is declared like Motorcycle class and assigns 4 to wheels and there is a getter method to return the value of wheels). 例如,如果您在代码中执行此操作(假设Truck类被声明为Motorcycle类并将4分配给wheel并且有一个getter方法来返回wheel的值)。

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

will print: 将打印:

Motorcycle has 4 wheels. 摩托车有4个轮子。

Maybe you'd like to think about the constructors you are using. 也许你想考虑一下你正在使用的构造函数。

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

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

public Motorcycle cycle = new Motorcycle(2);

The Motorcycle uses the super constructor that knows what to do with the parameter. Motorcycle使用知道如何处理参数的超级构造函数。 It automatically sets wheels to 2. 它会自动将车轮设置为2。

If you make a static variable in your objects it will be the same for every Vehicle class you will make, even when you would make another subclass for your abstract Vehicle class. 如果在对象中创建一个静态变量,那么对于您将要创建的每个Vehicle类,它都是相同的,即使您要为抽象Vehicle类创建另一个子类。 This because of the "nature" of any static variable. 这是因为任何静态变量的“性质”。

I think you want to use a non-static variable so that for every instance of any subclass of the abstract Vehicle class you can determine the value of the wheels and that is done as following: 我想你想使用一个非静态变量,这样对于抽象Vehicle类的任何子类的每个实例,你都可以确定轮子的值,并按如下方式完成:

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

and any subclass: 和任何子类:

public foo extends Vehicle{

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

You could also do this for the static variable but then you will change it for every instance of any subclass of Vehicle 您也可以为静态变量执行此操作,但随后您将为Vehicle的任何子类的每个实例更改它

Hope i helped you 希望我能帮助你

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM