可以枚举分类添加新的元素?

我想采取一个现有的枚举,并添加更多的元素,如下所示:

enum A {a,b,c} enum B extends A {d} /*B is {a,b,c,d}*/ 

这在Java中可能吗?

不,你不能用Java来做这件事。 除此之外, d可能大概是A一个实例(考虑到“扩展”的正常概念),但是只知道A用户不会知道这个 – 这就打破了枚举的点,已知的一组值。

如果您可以告诉我们更多关于如何使用这个功能的信息,我们可能会提出其他解决方案。

枚举代​​表了可能值的完整列举。 所以(无益的)答案是否定的。

作为一个真正的问题的例子,平日,周末和工会,星期几。 我们可以在几天之内定义所有的日子,但是这样我们就不能代表周末和周末特别的属性。

我们可以做的是有三个枚举类型,在平日/周末日和星期几之间映射。

 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; } 

另外,我们可以有一个开放式的接口,用于星期几:

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

或者我们可以结合这两种方法:

 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() { ... } } 

推荐的解决方案是可扩展的枚举模式 。

这涉及到创建一个接口,并使用您当前使用枚举的地方。 然后使枚举实现接口。 您可以通过使新的枚举扩展接口来添加更多的常量。

在下面你的ENUM只是一个由编译器生成的常规类。 生成的类扩展了java.lang.Enum 。 无法扩展生成的类的技术原因是生成的类是final 。 这个主题讨论了它是最终的概念上的原因。 但我会把这个机制加入讨论。

这是一个测试枚举:

 public enum TEST { ONE, TWO, THREE; } 

由javap产生的代码:

 public final class TEST extends java.lang.Enum<TEST> { public static final TEST ONE; public static final TEST TWO; public static final TEST THREE; static {}; public static TEST[] values(); public static TEST valueOf(java.lang.String); } 

可以想象,你可以自己输入这个类,并放弃“最终”。 但编译器阻止您直接扩展“java.lang.Enum”。 你可以决定不扩展java.lang.Enum,但是你的类和它的派生类不会是一个java.lang.Enum的实例,这对你来说可能并不重要!

 enum A {a,b,c} enum B extends A {d} /*B is {a,b,c,d}*/ 

可以写成:

 public enum All { a (ClassGroup.A,ClassGroup.B), b (ClassGroup.A,ClassGroup.B), c (ClassGroup.A,ClassGroup.B), d (ClassGroup.B) ... 
  • ClassGroup.B.getMembers()包含{a,b,c,d}

它是如何有用的:假设我们想要这样的事情:我们有事件,我们正在使用枚举。 这些枚举可以通过类似的处理进行分组。 如果我们有很多元素的操作,那么一些事件开始运行,一些只是一步,另一些结束操作。 要收集这样的操作,避免长时间切换的情况下,我们可以把它们分组为例子和使用:

 if(myEvent.is(State_StatusGroup.START)) makeNewOperationObject().. if(myEnum.is(State_StatusGroup.STEP)) makeSomeSeriousChanges().. if(myEnum.is(State_StatusGroup.FINISH)) closeTransactionOrSomething().. 

例:

 public enum AtmOperationStatus { STARTED_BY_SERVER (State_StatusGroup.START), SUCCESS (State_StatusGroup.FINISH), FAIL_TOKEN_TIMEOUT (State_StatusGroup.FAIL, State_StatusGroup.FINISH), FAIL_NOT_COMPLETE (State_StatusGroup.FAIL, State_StatusGroup.STEP), FAIL_UNKNOWN (State_StatusGroup.FAIL, State_StatusGroup.FINISH), (...) private AtmOperationStatus(StatusGroupInterface ... pList){ for (StatusGroupInterface group : pList){ group.addMember(this); } } public boolean is(StatusGroupInterface with){ for (AtmOperationStatus eT : with.getMembers()){ if( eT .equals(this)) return true; } return false; } // Each group must implement this interface private interface StatusGroupInterface{ EnumSet<AtmOperationStatus> getMembers(); void addMember(AtmOperationStatus pE); } // DEFINING GROUPS public enum State_StatusGroup implements StatusGroupInterface{ START, STEP, FAIL, FINISH; private List<AtmOperationStatus> members = new LinkedList<AtmOperationStatus>(); @Override public EnumSet<AtmOperationStatus> getMembers() { return EnumSet.copyOf(members); } @Override public void addMember(AtmOperationStatus pE) { members.add(pE); } static { // forcing initiation of dependent enum try { Class.forName(AtmOperationStatus.class.getName()); } catch (ClassNotFoundException ex) { throw new RuntimeException("Class AtmEventType not found", ex); } } } } //Some use of upper code: if (p.getStatus().is(AtmOperationStatus.State_StatusGroup.FINISH)) { //do something }else if (p.getStatus().is(AtmOperationStatus.State_StatusGroup.START)) { //do something } 

添加一些更高级的:

 public enum AtmEventType { USER_DEPOSIT (Status_EventsGroup.WITH_STATUS, Authorization_EventsGroup.USER_AUTHORIZED, ChangedMoneyAccountState_EventsGroup.CHANGED, OperationType_EventsGroup.DEPOSIT, ApplyTo_EventsGroup.CHANNEL), SERVICE_DEPOSIT (Status_EventsGroup.WITH_STATUS, Authorization_EventsGroup.TERMINAL_AUTHORIZATION, ChangedMoneyAccountState_EventsGroup.CHANGED, OperationType_EventsGroup.DEPOSIT, ApplyTo_EventsGroup.CHANNEL), DEVICE_MALFUNCTION (Status_EventsGroup.WITHOUT_STATUS, Authorization_EventsGroup.TERMINAL_AUTHORIZATION, ChangedMoneyAccountState_EventsGroup.DID_NOT_CHANGED, ApplyTo_EventsGroup.DEVICE), CONFIGURATION_4_C_CHANGED(Status_EventsGroup.WITHOUT_STATUS, ApplyTo_EventsGroup.TERMINAL, ChangedMoneyAccountState_EventsGroup.DID_NOT_CHANGED), (...) 

在上面,如果我们有一些失败(myEvent.is(State_StatusGroup.FAIL)),然后迭代以前的事件,我们可以很容易地检查是否必须恢复资金转移:

 if(myEvent2.is(ChangedMoneyAccountState_EventsGroup.CHANGED)) rollBack().. 

它可以用于:

  1. 包括关于处理逻辑的明确的元数据,而不需要记住
  2. 实现一些多继承
  3. 我们不想使用类结构,例如。 用于发送简短的状态消息

以下是我如何发现如何将enum扩展为其他枚举的方法,这是一个非常直接的方法:

你有一个共同常数的枚举:

 public interface ICommonInterface { String getName(); } public enum CommonEnum implements ICommonInterface { P_EDITABLE("editable"), P_ACTIVE("active"), P_ID("id"); private final String name; EnumCriteriaComun(String name) { name= name; } @Override public String getName() { return this.name; } } 

那么你可以尝试做一个手动扩展这种方式:

 public enum SubEnum implements ICommonInterface { P_EDITABLE(CommonEnum.P_EDITABLE ), P_ACTIVE(CommonEnum.P_ACTIVE), P_ID(CommonEnum.P_ID), P_NEW_CONSTANT("new_constant"); private final String name; EnumCriteriaComun(CommonEnum commonEnum) { name= commonEnum.name; } EnumCriteriaComun(String name) { name= name; } @Override public String getName() { return this.name; } } 

当然,每当你需要扩展一个常量时,你必须修改你的SubEnum文件。

如果你错过了,在Joshua Bloch的书“ Java Effective,2nd edition ”中有一章。

  • 第6章 – 枚举和注释
    • 项目34: 用接口仿真可扩展枚举

在这里提取。

只是结论:

使用接口来模拟可扩展枚举的一个小缺点是实现不能从一个枚举类型继承到另一个枚举类型。 在我们的操作示例中,存储和检索与操作相关联的符号的逻辑在BasicOperation和ExtendedOperation中被复制。 在这种情况下,没有关系,因为只有很少的代码是重复的。 如果共享功能数量较多,则可以将其封装在助手类或静态帮助程序方法中,以消除代码重复。

总之,虽然不能编写可扩展的枚举类型,但可以通过编写一个接口来使用实现该接口的基本枚举类型来模拟它。 这允许客户编写自己的实现接口的枚举。 这些枚举然后可以在基本枚举类型可以使用的任何地方使用,假设API是根据接口编写的。

我倾向于避免枚举,因为它们是不可扩展的。 要保持OP的例子,如果A在库中,B在你自己的代码中,那么如果它是一个枚举,则不能扩展A. 我有时候会这样替换枚举:

 // access like enum: Aa public class A { public static final A a = new A(); public static final A b = new A(); public static final A c = new A(); /* * In case you need to identify your constant * in different JVMs, you need an id. This is the case if * your object is transfered between * different JVM instances (eg. save/load, or network). * Also, switch statements don't work with * Objects, but work with int. */ public static int maxId=0; public int id = maxId++; public int getId() { return id; } } public class B extends A { /* * good: you can do like * A x = getYourEnumFromSomeWhere(); * if(x instanceof B) ...; * to identify which enum x * is of. */ public static final A d = new A(); } public class C extends A { /* Good: e.getId() != d.getId() * Bad: in different JVMs, C and B * might be initialized in different order, * resulting in different IDs. * Workaround: use a fixed int, or hash code. */ public static final A e = new A(); public int getId() { return -32489132; }; } 

有一些坑可以避免,请参阅代码中的注释。 根据您的需要,这是一个可靠的,可扩展的枚举替代方案。

这是我如何增强静态初始化器中运行时检查的枚举继承模式。 BaseKind#checkEnumExtender检查“扩展”枚举是否以完全相同的方式声明基本枚举的所有值,所以#name()#ordinal()保持完全兼容。

仍然存在用于声明值的复制粘贴,但是如果有人在基类中添加或修改了一个值,而不更新扩展名,程序就会快速失败。

不同的枚举相互之间的共同行为:

 public interface Kind { /** * Let's say we want some additional member. */ String description() ; /** * Standard {@code Enum} method. */ String name() ; /** * Standard {@code Enum} method. */ int ordinal() ; } 

基础枚举,验证方法:

 public enum BaseKind implements Kind { FIRST( "First" ), SECOND( "Second" ), ; private final String description ; public String description() { return description ; } private BaseKind( final String description ) { this.description = description ; } public static void checkEnumExtender( final Kind[] baseValues, final Kind[] extendingValues ) { if( extendingValues.length < baseValues.length ) { throw new IncorrectExtensionError( "Only " + extendingValues.length + " values against " + baseValues.length + " base values" ) ; } for( int i = 0 ; i < baseValues.length ; i ++ ) { final Kind baseValue = baseValues[ i ] ; final Kind extendingValue = extendingValues[ i ] ; if( baseValue.ordinal() != extendingValue.ordinal() ) { throw new IncorrectExtensionError( "Base ordinal " + baseValue.ordinal() + " doesn't match with " + extendingValue.ordinal() ) ; } if( ! baseValue.name().equals( extendingValue.name() ) ) { throw new IncorrectExtensionError( "Base name[ " + i + "] " + baseValue.name() + " doesn't match with " + extendingValue.name() ) ; } if( ! baseValue.description().equals( extendingValue.description() ) ) { throw new IncorrectExtensionError( "Description[ " + i + "] " + baseValue.description() + " doesn't match with " + extendingValue.description() ) ; } } } public static class IncorrectExtensionError extends Error { public IncorrectExtensionError( final String s ) { super( s ) ; } } } 

扩展示例:

 public enum ExtendingKind implements Kind { FIRST( BaseKind.FIRST ), SECOND( BaseKind.SECOND ), THIRD( "Third" ), ; private final String description ; public String description() { return description ; } ExtendingKind( final BaseKind baseKind ) { this.description = baseKind.description() ; } ExtendingKind( final String description ) { this.description = description ; } } 

自己也有同样的问题,我想发表我的观点。 我认为这样做有几个激励因素:

  • 你想有一些相关的枚举代码,但在不同的类。 在我的例子中,我有一个基类,在关联的枚举中定义了几个代码。 在稍后的日子(今天!),我想为基类提供一些新的功能,这也意味着枚举的新代码。
  • 派生类将既支持基类的枚举也支持它自己的。 没有重复的枚举值! 所以:如何为包含父类的枚举的子类及其新值包含一个枚举。

使用一个接口并不能真正减少它:你可能会意外地得到重复的枚举值。 不可取。

我最后只是结合了枚举:这确保了不会有任何重复的值,代价是与相关类没有紧密联系。 但是,我认为重复的问题是我主要关心的问题。

为了帮助理解为什么在语言实现级别扩展枚举不合理,考虑如果将扩展枚举的实例传递给仅了解基类枚举的例程,会发生什么情况。 编译器承诺的一个开关覆盖了所有的情况实际上不会覆盖那些扩展的枚举值。

这进一步强调,Java枚举值不是整数,例如C是,例如:使用Java Enum作为数组索引,你必须明确地要求它的ordinal()成员,给一个Java枚举一个任意的整数值,你必须添加一个明确的领域为那名为成员的引用。

这不是对OP的愿望的评论,只是为什么Java不会永远不会这样做。

基于@汤姆霍廷 – tackline答案我们添加开关支持,

 interface Day<T> { ... T valueOf(); } public enum Weekday implements Day<Weekday> { MON, TUE, WED, THU, FRI; Weekday valueOf(){ return valueOf(name()); } } public enum WeekendDay implements Day<WeekendDay> { SAT, SUN; WeekendDay valueOf(){ return valueOf(name()); } } Day<Weekday> wds = Weekday.MON; Day<WeekendDay> wends = WeekendDay.SUN; switch(wds.valueOf()){ case MON: case TUE: case WED: case THU: case FRI: } switch(wends.valueOf()){ case SAT: case SUN: } 

我的代码,如下所示:

 // enum A { a, b, c } static final Set<Short> enumA = new LinkedHashSet<>(Arrays.asList(new Short[]{'a','b','c'})); // enum B extends A { d } static final Set<Short> enumB = new LinkedHashSet<>(enumA); static { enumB.add((short) 'd'); // If you have to add more elements: // enumB.addAll(Arrays.asList(new Short[]{ 'e', 'f', 'g', '♯', '♭' })); } 

LinkedHashSet提供了每个条目只存在一次,并且它们的顺序被保留。 如果顺序无关紧要,则可以使用HashSet 。 以下代码在Java中是不可能的:

 for (A a : B.values()) { // enum B extends A { d } switch (a) { case a: case b: case c: System.out.println("Value is: " + a.toString()); break; default: throw new IllegalStateException("This should never happen."); } } 

代码可以写成如下:

 for (Short a : enumB) { switch (a) { case 'a': case 'b': case 'c': System.out.println("Value is: " + new String(Character.toChars(a))); break; default: throw new IllegalStateException("This should never happen."); } } 

从Java 7开始,你甚至可以用String来做同样的事情:

 // enum A { BACKWARDS, FOREWARDS, STANDING } static final Set<String> enumA = new LinkedHashSet<>(Arrays.asList(new String[] { "BACKWARDS", "FOREWARDS", "STANDING" })); // enum B extends A { JUMP } static final Set<String> enumB = new LinkedHashSet<>(enumA); static { enumB.add("JUMP"); } 

使用枚举替换:

 for (String a : enumB) { switch (a) { case "BACKWARDS": case "FOREWARDS": case "STANDING": System.out.println("Value is: " + a); break; default: throw new IllegalStateException("This should never happen."); } } 

希望这个我的同事的优雅的解决方案,甚至在这个长篇文章中看到,我想分享这种方法的子类化,遵循接口方法和超越。

请注意,我们在这里使用自定义异常,除非您将其替换为异常,否则此代码将无法编译。

文件是广泛的,我希望这是大多数人可以理解的。

每个子类的枚举需要实现的接口。

 public interface Parameter { /** * Retrieve the parameters name. * * @return the name of the parameter */ String getName(); /** * Retrieve the parameters type. * * @return the {@link Class} according to the type of the parameter */ Class<?> getType(); /** * Matches the given string with this parameters value pattern (if applicable). This helps to find * out if the given string is a syntactically valid candidate for this parameters value. * * @param valueStr <i>optional</i> - the string to check for * @return <code>true</code> in case this parameter has no pattern defined or the given string * matches the defined one, <code>false</code> in case <code>valueStr</code> is * <code>null</code> or an existing pattern is not matched */ boolean match(final String valueStr); /** * This method works as {@link #match(String)} but throws an exception if not matched. * * @param valueStr <i>optional</i> - the string to check for * @throws ArgumentException with code * <dl> * <dt>PARAM_MISSED</dt> * <dd>if <code>valueStr</code> is <code>null</code></dd> * <dt>PARAM_BAD</dt> * <dd>if pattern is not matched</dd> * </dl> */ void matchEx(final String valueStr) throws ArgumentException; /** * Parses a value for this parameter from the given string. This method honors the parameters data * type and potentially other criteria defining a valid value (eg a pattern). * * @param valueStr <i>optional</i> - the string to parse the parameter value from * @return the parameter value according to the parameters type (see {@link #getType()}) or * <code>null</code> in case <code>valueStr</code> was <code>null</code>. * @throws ArgumentException in case <code>valueStr</code> is not parsable as a value for this * parameter. */ Object parse(final String valueStr) throws ArgumentException; /** * Converts the given value to its external form as it is accepted by {@link #parse(String)}. For * most (ordinary) parameters this is simply a call to {@link String#valueOf(Object)}. In case the * parameter types {@link Object#toString()} method does not return the external form (eg for * enumerations), this method has to be implemented accordingly. * * @param value <i>mandatory</i> - the parameters value * @return the external form of the parameters value, never <code>null</code> * @throws InternalServiceException in case the given <code>value</code> does not match * {@link #getType()} */ String toString(final Object value) throws InternalServiceException; } 

实现ENUM基类。

 public enum Parameters implements Parameter { /** * ANY ENUM VALUE */ VALUE(new ParameterImpl<String>("VALUE", String.class, "[A-Za-z]{3,10}")); /** * The parameter wrapped by this enum constant. */ private Parameter param; /** * Constructor. * * @param param <i>mandatory</i> - the value for {@link #param} */ private Parameters(final Parameter param) { this.param = param; } /** * {@inheritDoc} */ @Override public String getName() { return this.param.getName(); } /** * {@inheritDoc} */ @Override public Class<?> getType() { return this.param.getType(); } /** * {@inheritDoc} */ @Override public boolean match(final String valueStr) { return this.param.match(valueStr); } /** * {@inheritDoc} */ @Override public void matchEx(final String valueStr) { this.param.matchEx(valueStr); } /** * {@inheritDoc} */ @Override public Object parse(final String valueStr) throws ArgumentException { return this.param.parse(valueStr); } /** * {@inheritDoc} */ @Override public String toString(final Object value) throws InternalServiceException { return this.param.toString(value); } } 

从基类“继承”的子类ENUM。

 public enum ExtendedParameters implements Parameter { /** * ANY ENUM VALUE */ VALUE(my.package.name.VALUE); /** * EXTENDED ENUM VALUE */ EXTENDED_VALUE(new ParameterImpl<String>("EXTENDED_VALUE", String.class, "[0-9A-Za-z_.-]{1,20}")); /** * The parameter wrapped by this enum constant. */ private Parameter param; /** * Constructor. * * @param param <i>mandatory</i> - the value for {@link #param} */ private Parameters(final Parameter param) { this.param = param; } /** * {@inheritDoc} */ @Override public String getName() { return this.param.getName(); } /** * {@inheritDoc} */ @Override public Class<?> getType() { return this.param.getType(); } /** * {@inheritDoc} */ @Override public boolean match(final String valueStr) { return this.param.match(valueStr); } /** * {@inheritDoc} */ @Override public void matchEx(final String valueStr) { this.param.matchEx(valueStr); } /** * {@inheritDoc} */ @Override public Object parse(final String valueStr) throws ArgumentException { return this.param.parse(valueStr); } /** * {@inheritDoc} */ @Override public String toString(final Object value) throws InternalServiceException { return this.param.toString(value); } } 

最后通用ParameterImpl来添加一些实用程序。

 public class ParameterImpl<T> implements Parameter { /** * The default pattern for numeric (integer, long) parameters. */ private static final Pattern NUMBER_PATTERN = Pattern.compile("[0-9]+"); /** * The default pattern for parameters of type boolean. */ private static final Pattern BOOLEAN_PATTERN = Pattern.compile("0|1|true|false"); /** * The name of the parameter, never <code>null</code>. */ private final String name; /** * The data type of the parameter. */ private final Class<T> type; /** * The validation pattern for the parameters values. This may be <code>null</code>. */ private final Pattern validator; /** * Shortcut constructor without <code>validatorPattern</code>. * * @param name <i>mandatory</i> - the value for {@link #name} * @param type <i>mandatory</i> - the value for {@link #type} */ public ParameterImpl(final String name, final Class<T> type) { this(name, type, null); } /** * Constructor. * * @param name <i>mandatory</i> - the value for {@link #name} * @param type <i>mandatory</i> - the value for {@link #type} * @param validatorPattern - <i>optional</i> - the pattern for {@link #validator} * <dl> * <dt style="margin-top:0.25cm;"><i>Note:</i> * <dd>The default validation patterns {@link #NUMBER_PATTERN} or * {@link #BOOLEAN_PATTERN} are applied accordingly. * </dl> */ public ParameterImpl(final String name, final Class<T> type, final String validatorPattern) { this.name = name; this.type = type; if (null != validatorPattern) { this.validator = Pattern.compile(validatorPattern); } else if (Integer.class == this.type || Long.class == this.type) { this.validator = NUMBER_PATTERN; } else if (Boolean.class == this.type) { this.validator = BOOLEAN_PATTERN; } else { this.validator = null; } } /** * {@inheritDoc} */ @Override public boolean match(final String valueStr) { if (null == valueStr) { return false; } if (null != this.validator) { final Matcher matcher = this.validator.matcher(valueStr); return matcher.matches(); } return true; } /** * {@inheritDoc} */ @Override public void matchEx(final String valueStr) throws ArgumentException { if (false == this.match(valueStr)) { if (null == valueStr) { throw ArgumentException.createEx(ErrorCode.PARAM_MISSED, "The value must not be null", this.name); } throw ArgumentException.createEx(ErrorCode.PARAM_BAD, "The value must match the pattern: " + this.validator.pattern(), this.name); } } /** * Parse the parameters value from the given string value according to {@link #type}. Additional * the value is checked by {@link #matchEx(String)}. * * @param valueStr <i>optional</i> - the string value to parse the value from * @return the parsed value, may be <code>null</code> * @throws ArgumentException in case the parameter: * <ul> * <li>does not {@link #matchEx(String)} the {@link #validator}</li> * <li>cannot be parsed according to {@link #type}</li> * </ul> * @throws InternalServiceException in case the type {@link #type} cannot be handled. This is a * programming error. */ @Override public T parse(final String valueStr) throws ArgumentException, InternalServiceException { if (null == valueStr) { return null; } this.matchEx(valueStr); if (String.class == this.type) { return this.type.cast(valueStr); } if (Boolean.class == this.type) { return this.type.cast(Boolean.valueOf(("1".equals(valueStr)) || Boolean.valueOf(valueStr))); } try { if (Integer.class == this.type) { return this.type.cast(Integer.valueOf(valueStr)); } if (Long.class == this.type) { return this.type.cast(Long.valueOf(valueStr)); } } catch (final NumberFormatException e) { throw ArgumentException.createEx(ErrorCode.PARAM_BAD, "The value cannot be parsed as " + this.type.getSimpleName().toLowerCase() + ".", this.name); } return this.parseOther(valueStr); } /** * Field access for {@link #name}. * * @return the value of {@link #name}. */ @Override public String getName() { return this.name; } /** * Field access for {@link #type}. * * @return the value of {@link #type}. */ @Override public Class<T> getType() { return this.type; } /** * {@inheritDoc} */ @Override public final String toString(final Object value) throws InternalServiceException { if (false == this.type.isAssignableFrom(value.getClass())) { throw new InternalServiceException(ErrorCode.PANIC, "Parameter.toString(): Bad type of value. Expected {0} but is {1}.", this.type.getName(), value.getClass().getName()); } if (String.class == this.type || Integer.class == this.type || Long.class == this.type) { return String.valueOf(value); } if (Boolean.class == this.type) { return Boolean.TRUE.equals(value) ? "1" : "0"; } return this.toStringOther(value); } /** * Parse parameter values of other (non standard types). This method is called by * {@link #parse(String)} in case {@link #type} is none of the supported standard types (currently * String, Boolean, Integer and Long). It is intended for extensions. * <dl> * <dt style="margin-top:0.25cm;"><i>Note:</i> * <dd>This default implementation always throws an InternalServiceException. * </dl> * * @param valueStr <i>mandatory</i> - the string value to parse the value from * @return the parsed value, may be <code>null</code> * @throws ArgumentException in case the parameter cannot be parsed according to {@link #type} * @throws InternalServiceException in case the type {@link #type} cannot be handled. This is a * programming error. */ protected T parseOther(final String valueStr) throws ArgumentException, InternalServiceException { throw new InternalServiceException(ErrorCode.PANIC, "ParameterImpl.parseOther(): Unsupported parameter type: " + this.type.getName()); } /** * Convert the values of other (non standard types) to their external form. This method is called * by {@link #toString(Object)} in case {@link #type} is none of the supported standard types * (currently String, Boolean, Integer and Long). It is intended for extensions. * <dl> * <dt style="margin-top:0.25cm;"><i>Note:</i> * <dd>This default implementation always throws an InternalServiceException. * </dl> * * @param value <i>mandatory</i> - the parameters value * @return the external form of the parameters value, never <code>null</code> * @throws InternalServiceException in case the given <code>value</code> does not match * {@link #getClass()} */ protected String toStringOther(final Object value) throws InternalServiceException { throw new InternalServiceException(ErrorCode.PANIC, "ParameterImpl.toStringOther(): Unsupported parameter type: " + this.type.getName()); } } 

I suggest you take the other way around approach.

Instead of extending the existing enumeration, create a larger one and create a subset of it. For exemple if you had an enumeration called PET and you wanted to extend it to ANIMAL you should do this instead:

 public enum ANIMAL { WOLF,CAT, DOG } EnumSet<ANIMAL> pets = EnumSet.of(ANIMAL.CAT, ANIMAL.DOG); 

Be careful, pets is not an immutable collections, you might want to use Guava or Java9 for more safety.