问题
Consider this class:
public class MyClassOfMystery {
public static final int NO_FLAGS = ~0;
public static final int FIRST_FLAG = 1;
public static final int SECOND_FLAG = 1 << 1;
public static final int THIRD_FLAG = 1 << 2;
public static final int FOURTH_FLAG = 1 << 3;
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {NO_FLAGS, FIRST_FLAG, SECOND_FLAG, THIRD_FLAG, FOURTH_FLAG})
public @interface MysteryFlags { }
... set flags, get flags, and use flags stuff.
}
I have often created something like this, and found that it would be useful to be able to iterate through all flags available in MysteryFlags
.
Can I iterate through my values set in MysteryFlags
?
This is what I have tried:
This printed ANNOTATION: @java.lang.annotation.Retention(value=SOURCE)
:
for (Annotation annotation : Flag.class.getAnnotations()) {
Log.d(TAG, String.format("ANNOTATION: %s", String.valueOf(annotation)));
}
This threw NPE on a null Array access
for (ExtraAction enm : Flag.class.getEnumConstants()) {
Log.d(TAG, String.format("ENUM: %s", String.valueOf(enm)));
}
These did not print anything out:
for (Field field : Flag.class.getFields()) {
Log.d(TAG, String.format("FIELD: %s", String.valueOf(field)));
}
and
for (Class<?> aClass : ExtraAction.class.getClasses()) {
Log.d(TAG, String.format("CLASS: %s", String.valueOf(aClass)));
}
I know I can just add the values to an array and iterate through that, but that requires storing another array. It is what I have done, but still wonder if there is a better way.
回答1:
I don't think you'll be able to query it like that at runtime. Your @MysterFlags
annotation has a retention policy of SOURCE
, which means it will be discarded by the compiler. Further, the @IntDef
annotation has a retention policy of CLASS
, which means it makes it through compile, but won't make it to runtime. That's why you are only seeing the @Retention
annotation in your first loop (that annotation has a retention policy of RUNTIME
).
回答2:
Well, this might be a bit old now - but I had a similar problem and the solution that I've found was:
MysteryFlags.class.getDeclaredFields()
It will return all the definitions declared.
回答3:
A compromise can be made if we declare our fields within the @interface
itself.
@Retention(RetentionPolicy.SOURCE)
@IntDef({MysteryFlags.NO_FLAGS, MysteryFlags.FIRST_FLAG, MysteryFlags.SECOND_FLAG, MysteryFlags.THIRD_FLAG, MysteryFlags.FOURTH_FLAG})
public @interface MysteryFlags {
// Note that all fields declared in an interface are implicitly public static final
int NO_FLAGS = ~0;
int FIRST_FLAG = 1;
int SECOND_FLAG = 1 << 1;
int THIRD_FLAG = 1 << 2;
int FOURTH_FLAG = 1 << 3;
}
When calling getFields()
on MisteryFlags.class
, all fields declared in the annotation are returned.
However, this means that any fields in the @interface
that are not defined within the @IntDef
will also be returned. IMO, this can work great if implemented by following a strict protocol.
来源:https://stackoverflow.com/questions/32160379/iterate-through-values-in-intdef-stringdef-or-any-def-class