Java: Dynamic type casting using enums
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. :)
精彩评论