Java:使用枚举实现动态类型转换

6

我正在尝试做类似以下的事情:

public void setContents(Object[] values)
{
    ...

        //A. this works
        mRank =
            ((String)(values[Columns.RANK.index])); 

        //B. doesn't work (entire line underlined by netbeans)
        mRank =
            (Columns.RANK.type.cast(values[Columns.RANK.index]));
        //incompatible types: required java,lang.String found: java.lang.Object

        //C. doesn't work (first RANK is underlined by netbeans)
        mRank =
            ((Columns.RANK.type)(values[Columns.RANK.index]));
        //cannot find symbol symbol: class RANK location: blah.blah.Columns

    ...
}

其中columns是一个内部枚举,如下所示:

public static enum Columns
{

    RANK(0, "Rank", String.class),
    NUMBER(1, "Number", Integer.class);

    public String text;
    public Class type;
    public int index;

    private Columns(int idx, String text, Class clasz)
    {
        this.type = clasz;
        this.text = text;
        this.index = idx;
    }
}

我理解为什么第B行不起作用,但我不明白为什么第C行也不起作用。如果我在类型转换之外的任何地方使用Columns.RANK.type,它都能正常工作,但是一旦我尝试使用该类进行类型转换,它就会编译错误,说在枚举中找不到RANK,这不应该是这种情况。
如何解决?
谢谢!

在JDK7中,javac将对您的原始Class类型发出原始类型警告,这应该使这类问题更加明显。 - Tom Hawtin - tackline
2个回答

4

C无法工作,因为Columns.RANK.type在编译时不可访问。

然而,B可以使用自定义的基于泛型的类来实现,而不是使用enum

class Columns<T>
{
    public static final Columns<String> RANK = new Columns<String>(0, "Rank", String.class);
    public static final Columns<Integer> NUMBER = new Columns<Integer>(1, "Number", Integer.class);

    public final Class<T> type;
    public final String text; 
    public final int index; 

    private Columns(int idx, String text, Class<T> clasz) 
    { 
        this.type = clasz; 
        this.text = text; 
        this.index = idx; 
    } 
}

@axtavt,非常好的解决方法!我还在等待另一个人来看看是否可以使用“枚举”来完成这个任务,否则你就是赢家。 - bguiz
@axtavt,仅供参考,类Columns<T>需要声明为public static class Column<T>,以便按建议工作 - 除非它们本身是静态的,否则内部类不能具有静态成员。 - bguiz

2
简而言之,使用枚举没有好的方法来做到这一点。 axtavt 的答案可能是最好的选择。trashgod 对于为什么 C 不起作用基本上是正确的,但可能需要更多的解释。
您需要考虑编译器如何解释 C。重要的是要区分 String 和 String.class。您有一个强制转换表达式,如 (String)foo。在这样的表达式中,您要进行强制转换的类型(在该示例中为 String)必须是类型的名称。您不会写 (String.class) foo,因为没有名为 String.class 的类。 (相反,String.class 只是一个对象,反映了类型 String 的 java.lang.Class 实例。)
因此,当编译器看到 (Columns.RANK.type)(values[Columns.RANK.index]),它会说“啊,这是一个强制转换表达式。因此,括号中的位必须是 bguiz 想要转换的类型的名称。”然后,它忠实地离开并寻找名为 Columns.RANK.type 的类型。由于它是类型的名称,因此期望它采用 my.package.containing.a.Type.AndMaybe.SomeInnerTypes 的形式。因此,它将其分成围绕 . 的部分,找到类型 Columns,然后去查找名为 RANK 的内部类型。没有这样的内部类型(常量 RANK 不计算),因此它失败并显示您引用的错误。
(如果它找到了,它将继续寻找另一个名为 type 的内部类型,同样,枚举中的字段不计算。)
请记住,编译器只是遵循一堆愚蠢的规则。它不在乎您的 Columns 枚举中也有一个常量 RANK。它也不知道类型名称通常是大写的。因此,它的错误消息有时对于头脑中带有所有这些上下文的人来说很难解释。 :)

+1:非常好的解释为什么编译器会报出错误。 - bguiz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接