我想采用一个现有的枚举,并向其添加更多元素,如下所示:
enum A {a,b,c}
enum B extends A {d}
/*B is {a,b,c,d}*/
这在Java中可行吗?
#1楼
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()..
它可用于:
- 包括关于处理逻辑的显式元数据,少记
- 实现一些多重继承
- 例如,我们不想使用类结构。 用于发送简短状态消息
#2楼
我倾向于避免枚举,因为它们不可扩展。 保留OP的示例,如果A在库中,而B在您自己的代码中,则如果A是枚举,则不能扩展A。 这就是我有时替换枚举的方式:
// access like enum: A.a
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; };
}
有一些陷阱要避免,请参见代码中的注释。 根据您的需要,这是枚举的可靠且可扩展的替代方案。
#3楼
在幕后,您的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);
}
可以想象,您可以自己输入此类,然后删除“ final”。 但是编译器阻止您直接扩展“ java.lang.Enum”。 您可以决定不扩展java.lang.Enum,但是您的类及其派生类将不是java.lang.Enum的实例……这对您实际上可能并不重要!
#4楼
不,您无法在Java中执行此操作。 除了别的什么, d
可能会是A
一个实例(考虑到“扩展”的正常概念),但是只知道A
用户不会知道它-这使枚举变得井井有条,已知的一组值。
如果您可以告诉我们更多有关如何使用它的信息,我们可能会建议其他解决方案。
#5楼
对此的推荐解决方案是可扩展的枚举模式 。
这涉及创建一个接口,并在您当前使用枚举的位置使用该接口。 然后使枚举实现接口。 您可以通过使新枚举也扩展接口来添加更多常量。
#6楼
枚举代表可能值的完整枚举。 因此,(无用的)答案是否定的。
作为一个实际问题的示例,以工作日,周末和工会为例。 我们可以在一周中的几天内定义所有日期,但随后我们将无法表示平日和周末的特殊属性。
我们所能做的是,有三种枚举类型,它们在工作日/周末和星期几之间进行映射。
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() { ... }
}
#7楼
这就是我通过静态初始化程序中的运行时检查来增强枚举继承模式的方式。 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 ;
}
}
#8楼
万一您错过了它,在Joshua Bloch出色的书“ Java Effective,第二版 ”中有一章。
- 第6章-枚举和注释
- 项目34: 使用接口模拟可扩展枚举
在这里提取。
只是结论:
使用接口模拟可扩展枚举的一个次要缺点是,实现不能从一种枚举类型继承到另一种枚举类型。 对于我们的Operation示例,在BasicOperation和ExtendedOperation中复制了存储和检索与操作关联的符号的逻辑。 在这种情况下,没有关系,因为几乎没有代码被重复。 如果共享功能更多,则可以将其封装在帮助器类或静态帮助器方法中,以消除代码重复。
总而言之,虽然您不能编写可扩展的枚举类型,但是可以通过编写一个接口来与实现该接口的基本枚举类型一起来模拟它。 这允许客户端编写自己的实现该接口的枚举。 然后,假定API是根据接口编写的,则可以在可以使用基本枚举类型的任何地方使用这些枚举。
#9楼
这是我发现如何将一个枚举扩展到其他枚举的一种方法,是一种非常直观的方法:
假设您有一个带有公共常量的枚举:
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文件。
#10楼
我的编码方式如下:
// 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.");
}
}
#11楼
基于@Tom Hawtin-大头贴答案,我们添加了开关支持,
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:
}
#12楼
希望在我的长篇文章中能看到我的一位同事的这种优雅解决方案,我想分享这种继承接口方法和其他方法的子类方法。
请注意,我们在此处使用自定义例外,除非您将其替换为例外,否则此代码不会编译。
文档内容广泛,希望对大多数人来说都是可以理解的。
每个子类枚举都需要实现的接口。
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 (e.g. 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 (e.g. 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());
}
}
#13楼
为了帮助理解为什么扩展Enum在语言实现级别上不合理,考虑将扩展Enum的实例传递给仅理解基本Enum的例程会发生什么情况。 编译器承诺的覆盖所有情况的开关实际上将不覆盖那些扩展的Enum值。
这进一步强调了Java Enum值不是整数,例如C:例如,要使用Java Enum作为数组索引,您必须明确要求其ordinal()成员,为Java Enum提供任意整数值,您必须添加一个明确的字段,并引用该命名成员。
这不是对OP的期望的评论,而是关于Java永远不会这样做的原因。
#14楼
我建议您采取另一种方法。
与其扩展现有的枚举,不如创建一个较大的枚举并创建其子集。 例如,如果您有一个称为PET的枚举并且想将其扩展为ANIMAL,则应改为:
public enum ANIMAL {
WOLF,CAT, DOG
}
EnumSet<ANIMAL> pets = EnumSet.of(ANIMAL.CAT, ANIMAL.DOG);
注意,宠物不是一成不变的收藏,您可能希望使用Guava或Java9来提高安全性。
#15楼
我本人也遇到过同样的问题,我想发表我的看法。 我认为做这样的事情有两个激励因素:
- 您希望有一些相关的枚举代码,但是要使用不同的类。 就我而言,我有一个基类,在关联的枚举中定义了几个代码。 稍后(今天!),我想为基类提供一些新功能,这也意味着枚举的新代码。
- 派生类将支持基类的枚举以及它自己的枚举。 没有重复的枚举值! 所以:如何为子类创建一个枚举,包括其父级的枚举及其新值。
使用接口并不能真正减少它:您可能会意外地得到重复的枚举值。 不可取。
最后,我仅合并了枚举:这确保了不会有任何重复的值,但要避免与其关联的类紧密关联。 但是,我认为重复的问题是我的主要关注点...