我希望通过将XResult的值复制到XStatus中来“扩展”枚举XStatus中的枚举XResult。
以下是我的表现方式。如果在XResult中找不到item,则说明为null:
private final String description;
private final Whatever funStuff;
private XStatus(){
String d=null;
Whatever f=null;
try{
XResult xResult = XResult.valueOf(this.name());
d = XResult.toString();
f = XResult.getWhatever();
}
catch (Exception e){
}
this.description = d;
this.funStuff = f;
}
问题是如果XResult不包含这样的项,则会抛出IllegalArgumentException。
问题:
除了不可靠的手动复制(不跟踪XResult的变化)之外,还有什么其他选择?
其余代码:
对于好奇的人来说,这是代码的其余部分,这个问题无关紧要:
private XStatus(final String d){
this.description = d;
}
public String toString(){
if (description==null || description.length()==0)
return doSomethingTo( this.name() );
return description;
}
public getWhatever(){ /*similar to toString */ }
答案 0 :(得分:0)
好吧,枚举原则上只是Java对象,因此您可以使用反射来测试XResult是否包含所需的值,甚至是add new values at runtime到您的枚举类。
答案 1 :(得分:0)
仅供参考,如果有人建议将其作为答案,我最初的方法是这样做:
private final String description;
private final Whatever funStuff;
private XStatus(XResult xResult){
this.description = xResult.toString();
this.funStuff = xResult.getWhatever();
}
这意味着,而不是声明
enum XStatus {
//from XResult
NOT_FOUND,
DELETED,
PROCESSED,
TBD,
blah, blah ...
}
我必须申报
enum XStatus {
//from XResult
NOT_FOUND(XResult.NOT_FOUND),
DELETED(XResult.DELETED),
PROCESSED(XResult.PROCESSED),
TBD(XResult.TBD),
blah, blah ...
}
答案 2 :(得分:0)
这是如何在没有valueOf的情况下通常使用O(1):
public enum XStatus {
;
private XStatus() {
XResult xr = Helper.NAMES.get(this.name()); // do whatever with
}
static {
Helper.NAMES = null; // get rid of the map
} // after the constants are instantiated
private static class Helper {
static Map<String, XResult> NAMES = new HashMap<String, XResult>();
static {
for(XResult xr : XResult.values()) {
NAMES.put(xr.name(), xr);
}
}
}
}
请注意,这与valueOf基本相同,但您不必尝试使用try-catch。当然valueOf只抛出RuntimeExceptions所以你只需捕获是否有不与XResult并行的常量。
另外,只要把它扔出去,一个更自动的解决方案就是这样:
public final class XStatus {
private XStatus(XResult xr) {
//
}
private static final XStatus[] TABLE; // or an EnumMap
// with Collections.unmodifiableMap
static {
XResult[] xrValues = XResult.values();
TABLE = new XStatus[xrValues.length];
for(XResult xr : xrValues) {
TABLE[xr.ordinal()] = new XStatus(xr);
}
}
public static XStatus xStatusFor(XResult xr) {
return TABLE[xr.ordinal()];
}
}
这将反映XResult 1:1,而不依赖于任何类型的String评估。你需要一个XResult来检索它相应的常量,但这就是重点。此外,如果出于某种原因XResult在您的控件之外进行更改,则无需更改XStatus。
答案 3 :(得分:0)
另一种技术可以解决您在将XResult类加载到应用程序时动态更改XResult类的问题,即使用字节操作框架(如f.e)在加载时简单地操作其内容。 Javassist。
然而,这需要您的应用程序之前没有加载枚举,并且您运行自己的类加载器,它将加载该类加载器中的枚举(以及访问枚举的所有类)(或者在类加载器的子类加载器中)加载了你修改过的枚举字节。)
在使用javassist时,您可以执行类似的操作(尚未使用枚举实现)
public byte[] modifyClass(String className)
{
try
{
// load the bytes from the .class file that actually contains the original definition of the XResult enum
byte[] xResultBytes = ...
// define a classpool javassist will use to find the definition for classes
ClassPool cp = ClassPool.getDefault();
// add a new search path for class definitions to the class path
cp = cp.insertClassPath(new ClassClassPath(this.getClass()));
// add the jar file containing java classes needed to the classpath
cp = cp.insertClassPath(jarFile.getAbsolutePath());
// as you do not have loaded XResult with any classloader yet you do not have a Class file of it
// so you need to provide the loaded bytes and the fully-qualified class name of the enum
cp = cp.appendClassPath(new ByteArrayClassPath(className, xResultBytes));
// now you are good to go with modifying the class
// first create a javassist classrepresentation of the bytes loaded
CtClass cc = cp.get(className);
// you can't modify frozen classes
if (!cc.isFrozen())
{
// you only want to instrument the XResult.class
if (className.endsWith("XResult")) // better replace it with the full name
{
// find, add, remove or rename annotations, fields and methods to your liking here
}
}
return cc.toBytecode();
}
catch (Exception e)
{
// handle error
}
}
在自定义类加载器中,您可以覆盖findClass
以将修改后的字节实际定义为XResult而不是原始字节:
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException
{
// instead of using the original bytes use the modified byte of the class
byte[] classBytes = modifyClass(className);
if (classBytes != null)
{
// this will actually create the Class<XResult> enum representation
return defineClass(className, classBytes, 0, classBytes.length);
}
throw new ClassNotFoundException(...);
}
您也可以使用javassist提供的加载程序代替自定义类加载器:
ClassPool pool = ClassPool.getDefault();
Loader cl = new Loader(pool);
CtClass ct = pool.get("test.Rectangle");
ct.setSuperclass(pool.get("test.Point"));
Class c = cl.loadClass("test.Rectangle");
Object rect = c.newInstance();
可能你应该反编译枚举类,看看枚举类实际包含什么,以及你想要摆脱什么部分。 F.e如果抛出的异常确实困扰你,你可以简单地删除该方法并将其替换为不抛出异常但只返回null的方法。
看一下javassist的解释性教程: