【问题标题】:Alternative to static overriding in javajava中静态覆盖的替代方案
【发布时间】:2018-09-22 23:02:11
【问题描述】:

我已经为此苦苦挣扎了一段时间。我想定义一组有限的类型,其中一些是其他类型的子类型,其中每种类型都由其属性的值定义。然后这些类型将用于访问它们的属性,并通过工厂方法创建它们的实例。

现在可能没有多大意义,所以假设我有这段代码。

abstract class Car {
    final int seats;
    final int maxSpeed;
    ...
}

abstract class DeliveryCar extends Car {
    final int maxload;
    ...
}

现在我想要拥有诸如 FamilyCarSportsCar 的超类型 CarHeavyTruck 的超类型 DeliveryCar 的类型,每种类型都有多个实例,困难的部分是实例变量不应该真的是“实例”变量 - 它们应该对每个 FamilyCar 具有相同的值,然后对于每个 SportsCar 和每个 HeavyTruck 的其他值应该具有相同的值,并且它们应该可以在没有实例的情况下访问。所以例如我希望能够写:

System.out.print("Sports cars' max. speed: " + SportsCar.maxSpeed);

我想到但没有解决的一些事情:

  • 静态值,但 java 不允许覆盖静态成员
  • 枚举,但在 java 中没有枚举的子类,因此每个不是 DeliveryCarCar 都必须有 maxload 和可能的其他成员
  • 模拟枚举,类似这样:
class CarType {
    final int seats;
    final int maxSpeed;
    ...
    static final CarType FAMILY_CAR = new CarType(5, 180);
    static final CarType SPORT_CAR = new CarType(2, 280);
    ...
    CarType(int seats, int maxSpeed) {
    ...
}

class DeliveryCarType extends CarType {
    final int maxload;
    ...
    static final DeliveryCarType HEAVY_TRUCK = new DeliveryCarType(3, 150, 500)
    ...
    DeliveryCarType(int seats, int maxSpeed, int maxLoad) {
    ...
}

它会做我需要的,但它也将是有效的,比如DeliveryCar.SPORTS_CAR

我不确定我想要实现的设计中是否存在一些根本性缺陷,但这让我非常烦恼,因为我似乎无法解决仅通过可覆盖的静态成员即可解决的问题,我认为一些其他语言(例如 Objective-C)实现。

编辑:我还阅读了this 讨论(以及其他内容),但那里的任何想法似乎都无法解决我的问题。

【问题讨论】:

  • 您想对这些值使用多态性吗?例如:List<? extends Car> listOfAnyCars ...; for(Car car : listOfAnyCars) System.out.println(car.maxSpeed); 应该打印不同的值吗?另外Car.maxSpeedSportsCar.maxSpeed 应该打印不同的值吗? (这两种结果都不可能)
  • @xtratic 只要汽车属于不同的子类型,它就应该打印不同的值。所以所有FamilyCar 的最大值都相同。速度,但不同于最大速度。 SportsCars 的速度。我希望这是有道理的。 Car.maxSpeed 不代表我要建模的任何内容。它的值可以用作子类型的默认值,可以覆盖它。

标签: java inheritance enums static singleton


【解决方案1】:

您不需要静态字段,只需使用常规受保护(或公共)字段。如果您想确保其他子类型无法覆盖它,可以在子类中将其设为 final...

abstract class  Car {
     protected int max = 5;
}

class Family extends Car {
    protected final int max = 10;
}

class Sport extends Car {
    protected final int max = 100;
}

class Other extends Car {
}

public static void main(String[] args) {
  System.out.println(new Family().max);
  System.out.println(new Sport().max);
  System.out.println(new Other().max);
}

给出输出: 10 100 5

【讨论】:

  • 是的,我知道这总是可能的,但我正在寻找更清洁的解决方案。我不喜欢你需要有一个实例来访问你事先知道的值,并且每个对象都必须有自己的每个变量的副本。我想如果对象很大,这两件事都会影响内存,这就是为什么我认为应该有更好的解决方案。
【解决方案2】:

首先,关于什么不起作用(纯静态的东西)的重要说明:

public static class Car {
    public final static String NAME = "Car";
    public static String getName() { return NAME; }
}

public static class SportsCar extends Car {
    public final static String NAME = "SportsCar";
    public static String getName() { return NAME; }
}

public static void main(String[] args) {
    Car c0 = new Car();
    System.out.println(c0.NAME);
    System.out.println(c0.getName());
    //  both print "Car"

    SportsCar c1 = new SportsCar();
    System.out.println(c1.NAME);
    System.out.println(c1.getName());
    // both print "SportsCar"

    Car c2 = new SportsCar();
    System.out.println(c2.NAME);
    System.out.println(c2.getName());
    // both print "Car" because c2 ""doesn't know"" that it's really a 'SportsCar'
    // this is an issue with your need for polymorphism with these values
}

如果您想要多态性,那么您需要有返回静态值的实例方法,并覆盖实例方法以返回其类的更新后的静态值。可能是这样的:

public static class Car {
    public final static String NAME = "Car"; 
    public final static int MAX_SPEED = 90;

    public String getName() { return NAME; }
    public int getMaxSpeed() { return MAX_SPEED; /* Car.MAX_SPEED */ }
    public String toString() { return getName() + ": maxSpeed= " + getMaxSpeed(); }
}

public static class SportsCar extends Car {
    @SuppressWarnings("hiding") public final static String NAME = "SportsCar";
    @SuppressWarnings("hiding") public final static int MAX_SPEED = 120;

    @Override public String getName() { return NAME; /* SportsCar.NAME */}
    @Override public int getMaxSpeed() { return MAX_SPEED; /* SportsCar.MAX_SPEED */ }
    // ** no new fields so just inherit 'toString()'
}

public static class DeliveryCar extends Car {
    @SuppressWarnings("hiding") public final static String NAME = "DeliveryCar";
    @SuppressWarnings("hiding") public final static int MAX_SPEED = 70;
    /* new field ........... */ public final static int MAX_LOAD = 250;

    @Override public String getName() { return NAME; /* DeliveryCar.NAME */}
    @Override public int getMaxSpeed() { return MAX_SPEED; /* DeliveryCar.MAX_SPEED */}
    /* new */ public int getMaxLoad() { return MAX_LOAD; /* DeliveryCar.MAX_LOAD */ }

    @Override public String toString() { return getName() + ": maxSpeed= " + getMaxSpeed() + ", maxLoad= " + getMaxLoad(); }
}

public static class DeliveryTruck extends DeliveryCar {
    @SuppressWarnings("hiding") public final static String NAME = "DeliveryTruck";
    @SuppressWarnings("hiding") public final static int MAX_LOAD = 1000;

    @Override public String getName() { return NAME; /* DeliveryTruck.NAME */}
    @Override public int getMaxLoad() { return MAX_LOAD; /* DeliveryTruck.MAX_LOAD */ }
    // ** no new fields so just inherit 'toString()'
}


public static void main(String[] args) {
    List<Car> list = Arrays.asList(new Car(), new Car(), new SportsCar(), new DeliveryCar(), new DeliveryTruck(), new SportsCar());
    for(Car car : list) {
        System.out.println(car);
    }
    System.out.println("Static Car maxSpeed = " + Car.MAX_SPEED);
    // warning, should access through DeliveryCar.MAX_SPEED since DeliveryTruck doesn't redefine it.
    System.out.println("Static DeliveryTruck maxSpeed = " + DeliveryTruck.MAX_SPEED);
}

我不是特别喜欢它,但它确实有效...如果不出意外,这至少是一次头脑风暴,希望能引导我们找到更好的解决方案。我很想听听你是否有更好的想法。

【讨论】:

  • 感谢代码的努力。它确实有效,但写 car.MAX_SPEED 而不是 car.getMaxSpeed() 也太容易了,而且一切似乎都工作得很好,但是正如你在第一个例子中展示的那样,它会给出错误的值
  • 坦率地说,无论如何都应该永远通过实例调用静态字段或方法,这通常被视为 Java 中的疏忽。您应该能够让您的 IDE 将此标记为警告或错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-05
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多