【问题标题】:Java: Dynamic type casting using enumsJava:使用枚举的动态类型转换
【发布时间】:2010-01-22 01:15:52
【问题描述】:

我正在尝试按照以下方式做一些事情:

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 类型发出 rawtypes lint 警告,这应该会使此类问题更加明显。

标签: java enums casting


【解决方案1】:

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,很好的解决方法!我仍在等待另一个,看看是否确实可以使用enum 来完成此操作,否则滴答声将交给您。
  • @axtavt,仅供参考,需要将 Columns&lt;T&gt; 类声明为 public static class Column&lt;T&gt;,以便它按建议工作 - 内部类不能有静态成员,除非它们本身是静态的。
【解决方案2】:

简短的回答是使用枚举没有好方法。 axtavt 的答案可能是您最好的选择。对于为什么C 不起作用,trashgod 基本上是正确的,但也许它可以使用更多解释。

您需要考虑编译器如何解释C。这里重要的是StringString.class 之间的区别。你有一个像(String)foo 这样的铸造表达式。在这样的表达式中,您要转换的类型(在该示例中,String)必须是类型的名称。你不会写(String.class)foo,因为没有名为String.class 的类。 (相反,String.class 只是一个对象,是 java.lang.Class 的一个实例,它反映了 String 类型。)

所以,当编译器看到(Columns.RANK.type)(values[Columns.RANK.index])时,它会说“啊,这是一个强制转换表达式。所以,开头括号中的位必须是bguiz想要的类型的name投给。”然后它尽职尽责地寻找一个名为Columns.RANK.type 的类型。因为它是一个类型的名称,所以它期望它是my.package.containing.a.Type.AndMaybe.SomeInnerTypes 的形式。因此,它围绕.s 将其拆分,找到Columns 类型,然后在Columns 中查找名为RANK 的内部类型。没有这样的内部类型(常量RANK 不计算在内),因此它会因您引用的错误而失败。

(如果发现,它将继续寻找另一个名为type 的内部类型,同样,枚举中的字段不会计算在内。)

请记住,编译器只是遵循一堆愚蠢的规则。不在乎您的Columns 枚举中是否还有一个常量RANK。它也不知道类型名称通常是大写的。因此,它的错误信息有时很难被头脑中带着所有这些上下文的人解释。 :)

【讨论】:

  • +1 :很好地解释了为什么编译器会吐出错误。
猜你喜欢
  • 2023-02-21
  • 2012-11-02
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多