好的,例如,假设我有一个名为“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
}
答案 0 :(得分:12)
如果'车轮'是静止的,只有一个,它将同时适用于所有车辆。因此,三轮车,摩托车,18轮卡车和福特都将拥有相同数量的车轮。
这对我没有意义。最好让'wheels'成为父类中的实例变量,但每个子类都设置得恰当。
但你可以试试
Vehicle.wheels = 2;
注意:自从您添加到问题中后,我正在添加我的答案。
我喜欢你在每个子类中都有静态的想法。但你应该把它们变成私人的。然后将一个抽象方法放在父类(Vehicle)中,如
public abstract BufferedImage getSprite();
然后每个直接子类必须具有相同的方法,并且它可以返回私有静态变量。
使变量成为静态,因此您只需加载一次。将它们设为私有,以便类本身之外的代码不会愚弄它并引入错误。如果可能的话,你可以让它们成为'final',这样类中的代码就不能在事后改变它并引入bug。 (一个'最终'变量不能改变它的值,但它的值的内容可能会改变。所以'最终'并不是一个很好的例子。)
答案 1 :(得分:6)
你要做的事情从根本上是有缺陷的。您可以使Motorcycle
初始化wheels
一次:
// Static initializer
static
{
wheels = 2;
}
...或每次创建实例时:
// Instance initializer
{
wheels = 2;
}
但是只有一个变量 - 不是Motorcycle
的一个,Truck
的一个等等。如果你对Truck
和{{Motorcycle
做同样的事情1}},然后最后初始化的那个将“赢”。
目前还不清楚你想如何使用这个字段 - 但是如果你只有一个静态字段,那么它只会有一个值 - 而不是每个子类一个。
答案 2 :(得分: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);
}
}
答案 3 :(得分:2)
我认为这是一种更优雅的方式
我要提议的内容仍然受到您需要实例的限制。我没有看到任何方法,因为您希望wheels
作为超类的一部分公开,但wheels
的值取决于Vehicle
的子类和内部没有实例的子类类型没有概念。
在我看来,' wheel'在这种情况下既不是静态也不是非静态属性。它是 元数据 类。指定类元数据的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 ;
}
在我看来,这是最优雅的解决方案。
答案 4 :(得分: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类的每次后续使用,无论是扩展还是实例化为对象,都将指向静态变量的内存中的相同位置。
为了在子类中使用静态变量,您必须在方法中使用它。所以,你本质上可以像这样重写你的摩托车类:
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个轮子。
答案 5 :(得分:0)
也许你想考虑一下你正在使用的构造函数。
public Vehicle(int wheels) {
this.wheels = wheels;
}
public Motorcycle(int wheels) {
super(wheels);
}
public Motorcycle cycle = new Motorcycle(2);
摩托车使用知道如何处理参数的超级构造函数。它会自动将轮子设置为2。
答案 6 :(得分:0)
如果你在对象中创建一个静态变量,那么对于你将要制作的每个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的任何子类的每个实例更改它
希望我帮助你