Can enums be subclassed to add new elements?

I want to take an existing enum and add more elements to it as follows:

enum A {a,b,c}

enum B extends A {d}

/*B is {a,b,c,d}*/

Is this possible in Java?


Solution 1:

No, you can't do this in Java. Aside from anything else, d would then presumably be an instance of A (given the normal idea of "extends"), but users who only knew about A wouldn't know about it - which defeats the point of an enum being a well-known set of values.

If you could tell us more about how you want to use this, we could potentially suggest alternative solutions.

Solution 2:

Enums represent a complete enumeration of possible values. So the (unhelpful) answer is no.

As an example of a real problem take weekdays, weekend days and, the union, days of week. We could define all days within days-of-week but then we would not be able to represent properties special to either weekdays and weekend-days.

What we could do, is have three enum types with a mapping between weekdays/weekend-days and days-of-week.

public enum Weekday {
    MON, TUE, WED, THU, FRI;
    public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay {
    SAT, SUN;
    public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
    MON, TUE, WED, THU, FRI, SAT, SUN;
}

Alternatively, we could have an open-ended interface for day-of-week:

interface Day {
    ...
}
public enum Weekday implements Day {
    MON, TUE, WED, THU, FRI;
}
public enum WeekendDay implements Day {
    SAT, SUN;
}

Or we could combine the two approaches:

interface Day {
    ...
}
public enum Weekday implements Day {
    MON, TUE, WED, THU, FRI;
    public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay implements Day {
    SAT, SUN;
    public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
    MON, TUE, WED, THU, FRI, SAT, SUN;
    public Day toDay() { ... }
}

Solution 3:

The recommended solution to this is the extensible enum pattern.

This involves creating an interface and using that where you currently use the enum. Then make the enum implement the interface. You can add more constants by making that new enum also extend the interface.