Могу ли я расширить класс и переопределить закрытый тип перечисления?
Если у меня есть класс, содержащий тип 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
.