泛型类型的 Java 枚举
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/3044796/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java enums in generic type
提问by Marcin Cylke
I'd like to create a generic enum-based mapper for IBatis. I'm doing this with the below code. This does have compile time errors, which I don't know how to fix. Maybe my solution is just plain wrong (keep in mind the use of IBatis), in such case please suggest something better.
我想为 IBatis 创建一个通用的基于枚举的映射器。我正在使用以下代码执行此操作。这确实有编译时错误,我不知道如何解决。也许我的解决方案完全错误(请记住使用 IBatis),在这种情况下,请提出更好的建议。
Any help appreciated.
任何帮助表示赞赏。
What I want to achieve is to define subsequent mappers as:
我想要实现的是将后续映射器定义为:
public class XEnumTypeHandler extends CommonEnumTypeHandler<X> {
}
The current code:
当前代码:
public class CommonEnumTypeHandler<T extends Enum> implements TypeHandlerCallback {
 public void setParameter(ParameterSetter ps, Object o) throws SQLException {
  if (o.getClass().isAssignableFrom(**T**)) { 
   ps.setString(((**T**) o).value().toUpperCase());
  } else
   throw new SQLException("Excpected ParameterType object than: " + o);
 }
 public Object getResult(ResultGetter rs) throws SQLException {
  Object o = valueOf(rs.getString());
  if (o == null)
   throw new SQLException("Unknown parameter type: " + rs.getString());
  return o;
 }
 public Object valueOf(String s) {
  for (T pt : T.**values()**) {
   if (pt.**value()**.equalsIgnoreCase(s))
    return pt;
  }
  return null;
 }
}
I've added error markings to the above code, the error messages are in order:
我在上面的代码中添加了错误标记,错误信息按顺序排列:
- T cannot be resolved
 - The method value() is undefined for the type T
 - The method values() is undefined for the type T
 - The method values() is undefined for the type T
 
- T无法解析
 - 未定义类型 T 的方法 value()
 - 方法 values() 对于类型 T 是未定义的
 - 方法 values() 对于类型 T 是未定义的
 
I've solved this issue with the following code:
我已经用以下代码解决了这个问题:
public class CommonEnumTypeHandler<T extends Enum> implements TypeHandlerCallback {
    Class<T> clazz;
    public CommonEnumTypeHandler(Class<T> clazz) {
        this.clazz = clazz;
    }
    public void setParameter(ParameterSetter ps, Object o) throws SQLException {
        if (o.getClass().isAssignableFrom(clazz)) {
            ps.setString(((T) o).name().toUpperCase());
        } else
            throw new SQLException("Excpected " + clazz + " object than: " + o);
    }
    public Object getResult(ResultGetter rs) throws SQLException {
        Object o = valueOf(rs.getString());
        if (o == null)
            throw new SQLException("Unknown parameter type: " + rs.getString());
        return o;
    }
    public Object valueOf(String s) {
        return Enum.valueOf(clazz, s);
    }
}
Inheriting from this class I do:
我从这个类继承:
public class SalesChannelTypeHandler extends CommonEnumTypeHandler<SalesChannel> {
    public SalesChannelTypeHandler() {
        super(SalesChannel.class);
    }
    public SalesChannelTypeHandler(Class<SalesChannel> clazz) {
        super(clazz);
    }
}
采纳答案by polygenelubricants
I'm not sure what you're doing (a general overview in words would be nice), but:
我不确定你在做什么(用文字概括一下会很好),但是:
- You can't do 
isAssignableFrom(T)(you need aClassobject), and you can't doinstanceof Teither (generics are non-reified). You maywant to passClass<T>type tokens instead. - Have you looked at 
EnumMap? 
- 你不能做
isAssignableFrom(T)(你需要一个Class对象),你也不能做instanceof T(泛型是非具体化的)。您可能希望改为传递Class<T>类型标记。 - 你看了
EnumMap吗? 
See also
也可以看看
- Java Tutorials/Runtime Type Tokens
 - Neal Gafter's Blog - Super Type Tokens
 - Josh Bloch - Typesafe Heterogenous Container (THC) pattern (PDF)
 
It's still not clear what is desired, but perhaps it's something along the lines of this:
目前还不清楚需要什么,但也许是这样的:
enum Color { BLACK, WHITE; }
public static void main(String[] args) {
    Color c = Enum.valueOf(Color.class, "black".toUpperCase());
    System.out.println(c); // prints "BLACK"
}
So we use Enum.valueOfthat takes a type token Class<T extends Enum<T>>, and ask it for the enumconstant with a given name. valueOfis NOTcase-insensitive, but by conventions, allconstants should be in uppercase, so we simply take the query string and turn it .toUpperCase().
所以我们使用Enum.valueOf它接受一个类型 token Class<T extends Enum<T>>,并要求它enum提供具有给定名称的常量。valueOf是不区分大小写的,而是由惯例,所有的常量应该是大写的,所以我们干脆把查询字符串,并把它.toUpperCase()。
回答by BalusC
As pointed by Polygenelubricants, you need to pass concrete runtime types around, e.g. Class<?>instead of syntactic compiletime types like generic parameters. Here's a rewrite how you could use it:
正如 Polygenelubricants 所指出的,您需要传递具体的运行时类型,例如,Class<?>而不是像泛型参数这样的语法编译时类型。这是重写如何使用它:
public abstract class CommonEnumTypeHandler<E extends Enum<E>> implements TypeHandlerCallback {
    private Class<E> enumClass;
    public CommonEnumTypeHandler(Class<E> enumClass) {
        this.enumClass = enumClass;
    }
    public void setParameter(ParameterSetter ps, Object o) throws SQLException {
        if (enumClass.isInstance(o)) {
            ps.setString((enumClass.cast(o)).name().toUpperCase());
        } else {
            throw new SQLException("Excpected ParameterType object than: " + o);
        }
    }
    public Object getResult(ResultGetter rs) throws SQLException {
        try {
            return Enum.valueOf(enumClass, rs.getString());
        } catch (IllegalArgumentException e) {
            throw new SQLException("Unknown parameter type: " + rs.getString(), e);
        }
    }
}
Which you can then use as follows:
然后您可以按如下方式使用它:
public class XEnumTypeHandler extends CommonEnumTypeHandler<X> {
    public XEnumTypeHandler() {
        super(X.class);
    }
}

