Могу ли я расширить класс и переопределить закрытый тип перечисления?

Если у меня есть класс, содержащий тип enum, могу ли я расширить этот класс и переопределить тип перечисления или добавить больше констант в это перечисление? Цель состоит в том, что пользователь сможет вызвать метод getColor(), не зная, является ли динамический объект базовым или производным. Например:

public class Car {

    private String name;

    private CarColors color;

    public enum CarColors {
        BLUE,
        GREEN
    }

    public Car(CarColors c) {
        color=c;
    }

    public CarColors getColor() {
        return color;
    }
}

public class RacingCar extends Car {

    private CarColors color;

    public RacingCar(CarColors c) {
        color=c;
    }

    public enum CarColors {
        BLUE,
        GREEN,
        RED
    }

    @Override //?????
    public CarColors getColor() {
        return color;
    }
}

и в основном:

Car racingCar = new RacingCar();
CarColors color = racingCar.getColor();

Ответы

Ответ 1

Вы не можете расширить enum. перечисления являются по существу классом final. Однако перечисления могут быть реализованы, поэтому в сочетании с дженериками вы получаете:

interface Color{

}
enum CarColor implements Color{
    BLUE,
    GREEN;
}
enum RacingCarColor implements Color{
    BLUE,
    GREEN,
    YELLOW;
}
class Vehicle<T extends Color> {
    protected T color;
    protected Vehicle(T color){
        this.color = color;
    }
    public T getColor(){
        return color;
    }
}

class Car extends Vehicle<CarColor>{ 
    public Car(CarColor color){
        super(color);
    }
}

class RacingCar extends Vehicle<RacingCarColor>{ 
    public RacingCar(RacingCarColor color){
        super(color);
    }
}

Voila!


Если вы хотите, чтобы тип был a Color и был перечислением, используйте эту привязку:

class Vehicle<T extends Enum<T> & Color> { ...

Или любопытный эквивалент:

class Vehicle<T extends Enum<? extends Color>> { ...

Ответ 2

Могу ли я расширить этот класс и переопределить тип перечисления или добавить больше констант в это перечисление?

Проблема в вашей ситуации называется скрывать, а не переопределять перечисления, а два выше перечисления не связаны друг с другом. Если вы указали переопределить как расширение типа перечисления, так как перечисление уже объявлено с ключевым словом final, вы не можете создать подтип типа перечисления для добавления дополнительных констант,

Цель состоит в том, что пользователь сможет вызвать метод getColor(), не зная, является ли динамический объект базовым или производным классом

Вы неверны в переопределении метода getColor. Тем не менее, вы сделали этот метод в подклассе RacingCar с той же подписью, что и метод в суперклассе Car. Вы по-прежнему забывали о возвращаемом типе, который должен быть таким же, как тип возврата в суперклассе, или быть подтипом возвращаемого типа переопределенного метода. У нас есть два разных перечисления, которые разделяют одно имя CarColors. Другими словами, полное имя переименования в подклассе - RacingCar.CarColors, а в суперклассе - Car.CarColors. Пока вы нарушили правило переопределения методов, а не тип возвращаемого типа, а не подтип типа возврата суперкласса.

В этом вопросе мы не можем создать подтип, и вы не хотите вставлять YELLOW в enum CarColors в Super Class Car, вот мое решение.

interface IColor{

}
enum CarColors implements IColor{
    BLUE,
    GREEN;
}
enum RacingCarColors implements IColor{
    BLUE,
    GREEN,
    YELLOW;
}
class Car {
    protected IColor color;
    public Car(IColor color){
        this.color = color;
    }
    public IColor getColor(){
        return color;
    }
}
class RacingCar extends Car{
    public RacingCar(IColor color){
        super(color);
    }
    public IColor getColor(){
        return color;
    }
}



public class Test{
    public static void main(String[] args) {
        Car car = new RacingCar(RacingCarColors.YELLOW);
        System.out.println(car.getColor());

    }
}

Подход по-прежнему переопределяет метод getColor, но я использовал один и тот же тип возврата IColor, что интерфейс - это супер тип двух перечислений в вашем примере. Это решение полностью соответствовало вашим ожиданиям, но это может быть сложно.

Ответ 3

Enums - это точно конечные внутренние классы, которые расширяют java.lang.Enum<E>. Вы не можете расширять, переопределять или наследовать enum.