开发者

Java: Dynamic type casting using enums

开发者 https://www.devze.com 2022-12-17 08:27 出处:网络
I am trying to do something along the lines of: public void setContents(Object[] values) { ... //A. this works

I am trying to do something along the lines of:

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

    ...
}

Where columns is an inner enum, like so:

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

I understand why line B doesn't work, but what I don't get is why C doesn't work. If I use Columns.RANK.type anywhere else other than in a type cast, it works fine, but one I attempt to do a typecast with the class, it compiles saying it cannot find RANK in the enum, which shouldn't be the case.

How to work around?

Thanks!


C doesn't work, because Columns.RANK.type is not accessible at compile time.

However, B can be implemented using a custom generic-based class instead of 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; 
    } 
}


The short answer is that there's no good way to do this with an enum. axtavt's answer is probably your best bet. trashgod is basically right about why C doesn't work, but perhaps it could use a bit more explanation.

You need to think about how the compiler is interpreting C. What's important here is the distinction between String and String.class. You've got a casting expression like (String)foo. In such an expression, the type that you're casting to (in that example, String) has to be the name of a type. You wouldn't write (String.class)foo, because there is no class called String.class. (Instead, String.class is just an object, an instance of java.lang.Class that reflects the type String.)

So, when the compiler sees (Columns.RANK.type)(values[Columns.RANK.index]), it says "ah, this is a casting expression. So, the bit in parens at the beginning must be the name of the type that bguiz wants to cast to." Then it dutifully goes off and looks for a type named Columns.RANK.type. Since it's the name of a type, it's expecting it to be of the form my.package.containing.a.Type.AndMaybe.SomeInnerTypes. Thus, it splits it up around the .s, finds the type Columns, and then goes off and looks for an inner type called RANK in Columns. There is no such inner type (the constant RANK doesn't count), so it fails with the error you quoted.

(If it found that, it would continue looking for another inner type called type, and again, the field in the enum wouldn't count.)

Remember that the compiler is just following a bunch of dumb rules. It doesn't care that you also have a constant RANK in your Columns enum. It also doesn't know that type names are usually upper-case. As a result its error messages are sometimes hard to interpret for a human who is carrying around all that context in his head. :)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号