使用变量调用 Java 对象常量

Invoke Java object constant using a variable

我是 Java 的新手,所以很难解释我想做什么。

我有一个抽象 class 调用几个对象常量,如下所示:

public abstract class Enchantment implements Keyed {
    /**
     * Provides protection against environmental damage
     */
    public static final Enchantment PROTECTION_ENVIRONMENTAL = new EnchantmentWrapper("protection");

在不同的文件中,我可以使用
Enchantment value = Enchantment.PROTECTION_ENVIRONMENTAL;

完美地访问它

但是,我正在尝试为此使用字符串变量。像这样:

String str = "PROTECTION_ENVIRONMENTAL";
Enchantment value = Enchantment.str;

显然这行不通。所以我做了很多研究,了解到我需要为此使用反射。使用此源代码的文档,我认为我正在寻找现场数据。所以我都试过了:

Field fld = Enchantment.class.getField("PROTECTION_ENVIRONMENTAL");
Field fld = Enchantment.class.getDeclaredField("PROTECTION_ENVIRONMENTAL");

但是这些返回了 NoSuchFieldException。正如我在上面所做的那样,我已经尝试了 getMethod()getDeclaredMethod() 同样没有运气。

我现在说这些可能是 "object constants"?我不确定如何称呼他们。但我现在肯定不知道如何让它工作,在我自己尝试了一切之后,我想是时候在这里寻求帮助了。

如果您知道枚举将是常量值,您可能想研究一下枚举;

public enum Enchantment {
    PROTECTION_ENVIRONMENTAL {
        public void cast() {
            // do enum-specific stuff here
        }
    },
    ANOTHER_ENCHANTMENT {
        public void cast() {
            // do enum-specific stuff here
        }
    },
    A_THIRD_ENCHANTMENT{
        public void cast() {
            // do enum-specific stuff here
        }
    };

    public abstract void cast();
}

枚举可以像 类 一样对待,并且具有方法和属性。您还可以与字符串相互转换 Enchantment.valueOf("PROTECTION_ENVIRONMENTAL") 但通常情况下,如果您正在从配置文件中读取数据 - 在代码中您会直接引用该值。

获得 Field 后,您需要使用实例调用 Field.get(Object)(在本例中为 class)。像,

Class<?> cls = Enchantment.class;
try {
    Field f = cls.getField("PROTECTION_ENVIRONMENTAL");
    System.out.println(f.get(cls));
} catch (Exception e) {
    e.printStackTrace();
}

既然你想要Enchantment,你可以然后测试你得到的实例是否可以分配给Enchantment.像,

Class<? extends Enchantment> cls = Enchantment.class;
try {
    Field f = cls.getField("PROTECTION_ENVIRONMENTAL");
    Object obj = f.get(cls);
    if (cls.isAssignableFrom(obj.getClass())) {
        Enchantment e = cls.cast(obj);
        System.out.println(e);
    }
} catch (Exception e) {
    e.printStackTrace();
}

但是 enum 方法更好

那条评论是正确的:你绝对不要在这里使用反射。

使用反射只有两个正当理由:

  • 您正在创建一个必须处理class它不知道的
  • 的框架
  • 您出于其他原因需要处理 class您在编译时不知道的问题

但是您的代码完全了解该附魔 class、它的功能等等。因此 reflection 是错误的做法。你自己想通了:做对很难,而在某些微妙的方面做错了也是对的。当你弄错时,它总是在 运行 时间爆炸。反射代码编译没有任何意义。它总是等着你 运行 吐在你的脸上。

因此,通过不回答来回答您的问题:使用地图。喜欢:

Map<String, Enchantment> enchantmentsByConstantName = new HashMap<>();
enchantmentsByConstantName.put("PROTECTION_ENVIRONMENTAL", PROTECTION_ENVIRONMENTAL);

或者,这些常量可以进入枚举,如其他答案中所述,但方式略有不同:

enum EnchantmentHolder {
  PROTECTION_ENVIRONMENTAL(new EnchantmentWrapper("protection")),
  ANOTHER_ENCHANTMENT(...)
  A_THIRD_ENCHANTMENT(...)
  ...;

  private Enchantment enchantment;

  private EnchantmentHolder(Enchantment enchantment) {
    this.entchantment = entchantment;
  }

  public Enchantment getEntchantment() { return entchantment; }