【问题标题】:Java -- Initializing superclass variables in subclasses?Java——在子类中初始化超类变量?
【发布时间】:2012-12-28 22:46:00
【问题描述】:

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

代码:

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

但以下不起作用:

public class Motorcycle extends Vehicle {
    wheels = 2;
}

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

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

我要为我的程序做的是为 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
}

【问题讨论】:

  • 我认为您误解了 Java 语言和 OO 编程的一些基础知识。将轮子作为静态看起来不正确。
  • 您可以扩展您的声明,即它“不起作用”。
  • @MikeQ Pun 有意?

标签: java variables subclass superclass


【解决方案1】:

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

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

但是你可以试试

Vehicle.wheels = 2;

注意:自从您添加到您的问题后,我将添加到我的答案中。

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

public abstract BufferedImage getSprite();

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

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

【讨论】:

  • 哇,谢谢!这可能是对我最有帮助的评论,而这正是我所需要的。
【解决方案2】:

您尝试做的事情存在根本缺陷。你可以Motorcycle初始化wheels一次:

// Static initializer
static
{
    wheels = 2;
}

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

// Instance initializer
{
    wheels = 2;
}

但是只有一个变量 - 没有一个用于Motorcycle,一个用于Truck 等等。如果你对TruckMotorcycle 都做了同样的事情,那么无论哪个被初始化最后会“赢”。

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      我要提出的仍然受到您需要实例的限制。我没有看到任何解决方法,因为您希望 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 ;
      }
      

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

      【讨论】:

        【解决方案5】:

        原始类声明:

        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.");
        

        将打印:

        摩托车有四个轮子。

        【讨论】:

          【解决方案6】:

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

          希望对你有帮助

          【讨论】:

            【解决方案7】:

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

            public Vehicle(int wheels) {
                this.wheels = wheels; 
            }
            
            public Motorcycle(int wheels) {
                super(wheels);
            }
            
            public Motorcycle cycle = new Motorcycle(2);
            

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

            【讨论】:

            • 所有摩托车可能都有相同数量的车轮。这表明将它放在构造函数的参数中是不正确的。
            猜你喜欢
            • 1970-01-01
            • 2017-01-09
            • 2016-08-19
            • 2015-11-21
            • 2022-06-10
            • 2016-01-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多