【问题标题】:Java enums in generic type泛型类型的 Java 枚举
【发布时间】:2010-06-15 11:47:06
【问题描述】:

我想为 IBatis 创建一个通用的基于枚举的映射器。我正在使用以下代码执行此操作。这确实有编译时错误,我不知道如何修复。也许我的解决方案是完全错误的(请记住使用 IBatis),在这种情况下,请提出更好的建议。

任何帮助表示赞赏。

我想要实现的是将后续映射器定义为:

public class XEnumTypeHandler extends CommonEnumTypeHandler<X> {
}

当前代码:

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

我已经在上面的代码中添加了错误标记,错误信息是按顺序排列的:

  • T 无法解析
  • 方法 value() 未定义 T型
  • 方法 values() 未定义 T型
  • 方法 values() 未定义 T型

我已经用下面的代码解决了这个问题:

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

我继承这个类:

public class SalesChannelTypeHandler extends CommonEnumTypeHandler<SalesChannel> {

    public SalesChannelTypeHandler() {
        super(SalesChannel.class);
    }

    public SalesChannelTypeHandler(Class<SalesChannel> clazz) {
        super(clazz);
    }

}

【问题讨论】:

  • 请添加编译器错误和您实际尝试实现的一些描述

标签: java generics enums


【解决方案1】:

我不确定你在做什么(用文字概括一下会很好),但是:

  • 你不能做isAssignableFrom(T)(你需要一个Class对象),你也不能做instanceof T(泛型是非具体化的)。您可能想改为传递 Class&lt;T&gt; 类型的令牌。
  • 你看过EnumMap吗?

另见


目前还不清楚需要什么,但也许是这样的:

enum Color { BLACK, WHITE; }

public static void main(String[] args) {
    Color c = Enum.valueOf(Color.class, "black".toUpperCase());
    System.out.println(c); // prints "BLACK"
}

所以我们使用Enum.valueOf,它接受类型标记Class&lt;T extends Enum&lt;T&gt;&gt;,并要求它提供具有给定名称的enum 常量。 valueOf NOT 不区分大小写,但按照惯例,all 常量应该是大写的,所以我们只需将查询字符串转换为.toUpperCase()。 p>

【讨论】:

  • @Marcin:同样,你不能做T.values(),但如果你传递Class&lt;T&gt; 的类型标记,你就可以做到。我举个例子,但我仍然不确定你在做什么。
  • 只是想写一个通用的“从字符串到定义类型的枚举”转换器。你传入一个字符串,说“test”并获取枚举 TestEnum.test
  • @Marcin:我理解你想要达到的目标,但面对现实吧:Generics are not reified in Java!您需要将其作为运行时方法参数而不是编译时泛型类型传递。也许构造函数有用?
  • @Marcin:所以你想要一个不区分大小写的 Enum.valueOf? java.sun.com/javase/6/docs/api/java/lang/…
  • @BalusC 好的,我现在明白了,但我不确定传递 Class 令牌是什么意思。你能给我看一些这种用法的例子吗?
【解决方案2】:

正如 Polygenelubricants 所指出的,您需要传递具体的运行时类型,例如Class&lt;?&gt; 而不是像泛型参数这样的语法编译时类型。这是重写的如何使用它:

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

然后您可以按如下方式使用:

public class XEnumTypeHandler extends CommonEnumTypeHandler<X> {
    public XEnumTypeHandler() {
        super(X.class);
    }
}

【讨论】:

  • 我仍然不确定 OP 想要什么,但无论如何我都会对此表示赞同。我确定你是对的 =)
  • setParameter 中,将isAssignableFrom 更改为enumClass.isInstance( o )
  • @BalusC:无论什么技能让你知道,我都想学。
  • @poly: learn JDBCDAO 并尝试重构所有内容并保持跨数据库兼容。换句话说:重新发明Hibernate / iBATIS / JPA ;)
  • @polygenelubricants。与客户的长时间可用性会议。我找到了类似的解决方案,但 Balus 领先我几秒钟。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多