8

好的,例如,假设我有一个名为“Vehicle”的抽象类。Vehicle 类除其他外还有一个名为wheels 的静态变量,该变量未初始化。我想要做的是从车辆类扩展其他子类,如“摩托车”和“卡车”,并在这些子类中初始化车轮。

代码:

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

但以下不起作用:

public class Motorcycle extends Vehicle {
    wheels = 2;
}

有没有办法有效地做到这一点?

编辑:感谢到目前为止所有回复的人。我知道制作实例可能比将它们全部放在单独的类中更好的方法,但是我没有完美地获得 java 的“静态”部分,所以我需要一些帮助。

我要为我的程序做的是为 Motorcycle 和 Truck 类设置单独的 sprite,我希望它们是静态的,这样我就不必在每次创建 Motorcycle 或 Truck 的实例时重新加载图像. 不过,除此之外,它们将具有几乎相同的属性,这就是为什么它们都将从 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
}
4

7 回答 7

12

如果“车轮”是静态的,则只有一个,它将同时适用于所有车辆。所以三轮车、摩托车、18 轮卡车和福特都将具有相同数量的车轮。

这对我来说没有意义。最好让“轮子”成为父类中的实例变量,但每个子类都适当地设置。

但是你可以试试

Vehicle.wheels = 2;

注意:自从您添加到问题中以来,我正在添加我的答案。

我喜欢你在每个子类中都有静态的想法。但是您应该将它们设为私有。然后在父类(Vehicle)中放一个抽象方法,如

public abstract BufferedImage getSprite();

然后每个直接子类必须具有相同的方法,并且它可以返回私有静态变量。

将变量设为静态,因此您只需加载一次。将它们设为私有,这样类本身之外的代码就不会愚弄它并引入错误。如果可能的话,您可以将它们设为“最终”,这样类本身的代码就不能在事后更改它并引入错误。('final' 变量的值不能改变,但其值的内容可以改变。所以 'final' 并不像它可能的那样美妙。)

于 2012-12-28T22:49:57.343 回答
6

你试图做的从根本上是有缺陷的。您可以进行一次Motorcycle初始化wheels

// Static initializer
static
{
    wheels = 2;
}

...或每次创建实例时:

// Instance initializer
{
    wheels = 2;
}

但是只有一个变量- 不是一个 for Motorcycle,一个 forTruck等等。如果你对两个Truckand做同样的事情Motorcycle,那么最后初始化的那个会“赢”。

目前还不清楚你想如何使用这个字段——但如果你只有一个静态字段,那么它只会有一个值——而不是每个子类一个值。

于 2012-12-28T22:48:56.257 回答
2

静态成员只定义一次,并且对每个扩展类都是通用的。更改其中一个值将影响所有其他值。这就是我相信您真正想要实现的目标:

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);
    }
}
于 2012-12-28T22:59:25.490 回答
2

我认为有一种更优雅的方式来做到这一点

我将要提出的仍然受到您需要实例的限制。我没有看到任何解决方法,因为您希望wheels作为超类的一部分公开,但是 的值wheels取决于子类,并且内部Vehicle没有没有实例的子类类型的概念。

在我看来,在这种情况下,“轮子”既不是静态属性也不是非静态属性。它是类元数据。Java 指定类元数据的方式是通过注解。

您需要的是这样的用户定义注释:

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

然后,您如下注释 Motorcyle:

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

在超类中,您提供了一个获取注释属性值的访问器。我建议您使用“惰性评估”方法,这样您就不会在每次需要值时都使用反射。

注意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 ;
}

在我看来,这是最优雅的解决方案。

于 2015-09-25T14:41:41.637 回答
2

原始类声明:

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 类的每次后续使用,无论是扩展还是实例化为对象,都将指向静态变量在内存中的相同位置。

为了在子类中使用静态变量,您必须在方法中使用它。因此,您实际上可以像这样重写您的 Motorcycle 类:

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

它会编译;但是,您可能不会得到您期望的结果。例如,如果您在代码中执行此操作(假设 Truck 类被声明为 Motorcycle 类并将 4 分配给车轮,并且有一个 getter 方法来返回车轮的值)。

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

将打印:

摩托车有4个轮子。

于 2016-06-29T18:27:51.410 回答
1

如果您在您的对象中创建一个静态变量,那么您将创建的每个 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 的任何子类的每个实例更改它

希望我帮助了你

于 2012-12-28T22:56:52.390 回答
0

也许您想考虑一下您正在使用的构造函数。

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

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

public Motorcycle cycle = new Motorcycle(2);

Motorcycle 使用知道如何处理参数的超级构造函数。它会自动将车轮设置为 2。

于 2012-12-28T22:53:25.367 回答