遍历 @IntDef、@StringDef 或任何 @Def 类中的值

13

考虑这个类:

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

我经常会创建这样的东西,并发现能够迭代 MysteryFlags 中的所有标志将非常有用。

我能否迭代在MysteryFlags中设置的值?

这是我尝试过的:


这将打印出ANNOTATION: @java.lang.annotation.Retention(value=SOURCE)

for (Annotation annotation : Flag.class.getAnnotations()) {
   Log.d(TAG, String.format("ANNOTATION: %s", String.valueOf(annotation)));
}

这导致了空数组访问的 NPE 异常。

for (ExtraAction enm : Flag.class.getEnumConstants()) {
   Log.d(TAG, String.format("ENUM: %s", String.valueOf(enm)));
}

这些没有输出任何内容:

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

我知道我可以将值添加到数组中并遍历该数组,但这需要存储另一个数组。虽然我已经这样做了,但仍然想知道是否有更好的方法。

那不应该是 NO_FLAGS = 0 吗? - Broatian
@Broatian No。Flags 表示按位操作。NO_FLAGS 将清除所有标志 - 因此 ~ - Chad Bingham
4个回答

9

我认为你不能在运行时像那样查询它。你的@MysterFlags注释具有SOURCE的保留策略,这意味着编译器将丢弃它。此外,@IntDef注释具有CLASS的保留策略,这意味着它通过编译,但不会到达运行时。这就是为什么你只在第一个循环中看到了@Retention注释(该注释具有RUNTIME的保留策略)。


1
如果我将保留策略更改为运行时,我能否进行迭代? - Chad Bingham
2
如果你想查看@IntDef的值,那么我认为不行。你无法更改该注释的保留策略。 - Jason Bullers

3
@interface中声明我们的字段,可以做出一个妥协
@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;
}

当调用MisteryFlags.class上的getFields()方法时,将返回注释中声明的所有字段。
但是,这意味着在@IntDef之外定义的任何@interface字段也会被返回。在我看来,如果按照严格的协议实现,这样可以很好地工作。

0

以下是如何进行迭代的方法。别忘了保留运行时!

class MyClassOfMystery {

    init {
        //How to iterate over Mysteries companion object
        Mysteries::class.java.declaredFields.map { it[0] }.filterIsInstance<String>()
    }

    @Retention(AnnotationRetention.RUNTIME)
    @StringDef(KING_ARTHUR, BIMINI_ROAD, NAZCA_LINES, STONEHENGE)
    annotation class Mysteries {
        companion object {
            const val KING_ARTHUR = "king_arthur"
            const val BIMINI_ROAD = "bimini_road"
            const val NAZCA_LINES = "nazca_lines"
            const val STONEHENGE = "stonehenge"
        }
    }
}

enter image description here


0

嗯,这可能有点过时了 - 但我遇到了类似的问题,我找到的解决方案是:

MysteryFlags.class.getDeclaredFields()

它将返回所有声明的定义。


如果在MyClassOfMystery中字段的声明方式与OP示例中不同,则此方法无法正常工作。 - Julius

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