【问题标题】:Java- variable that's static, but extended subclasses don't share the valueJava- 静态变量,但扩展子类不共享值
【发布时间】:2017-03-22 13:25:37
【问题描述】:

假设我有一堂课:

public abstract class Foo{
  public static int i = 0;
}

我想这样当我有 2 个额外的类时:

public class Bar extends Foo{
   public Bar(){ i=1; }
}  

public class t extends Foo{
   public t(){ i=-1;}
}

那 Bar.i 和 t.i 不是同一个值,而是它们各自的子类的静态值。

这是如何正确完成的?

这是一个更好的例子:

说我有课:

public abstract class vehicle{
  public static int tires;
}

我有两个子类:

public class car extends vehicle{
  public car(){
    //ALL cars have 4 tires. this is static to cars.
    tires = 4;
  }
}

public class motorcycle extends vehicle{
  public motorcycle(){
    //All motorcycles have 2 tires. this is static to motorcycles.
    tires = 2;
  }
}

很明显,汽车和摩托车确实有相同数量的轮胎,但我仍然希望能够同时访问 car.tires 和 motor.tires,分别返回 4 和 2。鉴于变量是车辆,我还希望能够调用 {variableName}.tires。我还希望以后能够添加更多这样的变量,例如另一个 int numberOfLights

【问题讨论】:

  • 所以,当你初始化一个Bar实例时,你将所有i变量设置为1?
  • 但是Bar.i 是未定义的。他们都是Foo.i
  • 如果您不希望子类共享,则必须在每个子类中定义一个static 变量。
  • 如果您需要 instance 变量,请删除 static
  • “那么我如何让子类继承它自己唯一的静态变量?”——你不知道。这是一个很好的例子,说明继承和静态不能很好地混合。

标签: java static virtual abstract


【解决方案1】:

你不能做你想做的事,静态不做虚拟查找。当您调用严格引用 Vehicle 上的类变量的 Vehicle.tires 时,它不会查看子类中的任何内容。

对于引用类上的静态变量的代码,它必须首先查看您在表达式中命名的特定类,然后沿着类层次结构向上(朝向根,java.lang.Object)直到它找到匹配项。因此,如果您调用 Motorcycle.tires 并且 Motorcycle 没有名为轮胎的静态变量,JVM 将在 Vehicle 上找到该名称的变量,但如果您调用 Vehicle.tires 则它不会在车辆上找到该名称的变量摩托车。

这与虚拟查找相反,在虚拟查找中,您的代码甚至可能不知道它正在处理的子类,它让对象在运行时计算出动态触发的行为。要使用静态变量和方法,调用它们的代码必须在编译时非常具体地说明它使用的子类。这就是他们称之为静态的原因,因为它不会改变。

这里最好避免使用静态。你可以有某种通用组件,车辆将委托给它以获取轮胎数量:

public Vehicle {
    private VehicleConfig config;
    public int getTireCount() {
        return config.getTireCount();
    }
}

将配置放在单独的对象中意味着您可以将其范围与包含它的事物分开管理。使用静态同样是一种管理对象范围的尝试,只是以一种不灵活的方式。

【讨论】:

    【解决方案2】:

    不过,它们确实共享价值。 Example

    // All print 0
    System.out.println(Foo.i);
    System.out.println(Bar.i);
    System.out.println(T.i);
    
    new Bar(); // all print 1
    System.out.println(Foo.i);
    System.out.println(Bar.i);
    System.out.println(T.i);
    
    new T(); // all now print -1
    System.out.println(Foo.i);
    System.out.println(Bar.i);
    System.out.println(T.i);
    

    您要么想要每个类中的变量,要么您实际上想要实例变量,而不是类变量。

    更新

    至于你更好的例子,你需要抽象方法,而不是静态变量。

    abstract class Vehicle {
        public abstract int getTires();
    }
    
    class Car extends Vehicle {
        @Override
        public int getTires() { return 4; }
    }
    
    class Motocycle extends Vehicle {
        @Override
        public int getTires() { return 2; }
    }
    

    【讨论】:

    • 我认为他希望它们在类之间共享——而只是在同一类的实例之间共享。
    【解决方案3】:

    这是你应该做的吗?我不完全确定你在问什么。

    public abstract class Foo{
    
    }    
    
    public class Bar extends Foo{
       public static int i = 0;
    }  
    and
    
    public class t extends Foo{
       public static int i = 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-31
      • 2011-01-31
      • 2015-10-14
      相关资源
      最近更新 更多