Вызвать константу Java-объекта, используя переменную - PullRequest
1 голос
/ 15 июня 2019

Я очень плохо знаком с Java, поэтому мне сложно объяснить, что я пытаюсь сделать.

У меня есть абстрактный класс, который вызывает несколько констант объекта, таких как:

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() одинаково, но безуспешно.

Я сейчас нахожусь в точке, что это, вероятно, "константы объекта"? Я не уверен, как их назвать. Но я определенно не знаю, как заставить это работать сейчас, и после всего, что я попробовал сам, я решил, что пришло время обратиться за помощью сюда.

Ответы [ 3 ]

3 голосов
/ 15 июня 2019

Этот комментарий замечен: вы абсолютно не используете отражение здесь.

Есть только две веские причины для использования отражения:

  • высоздаем фреймворк, который имеет дело с классами, о которых он не знает, о
  • , по какой-то другой причине вы имеете дело с классами, о которых вы не знаете во время компиляции

Но ваш код прекрасно знает об этом классе Enchantment, его возможностях и так далее.Поэтому отражение - неправильный подход.Вы сами это поняли: чертовски трудно понять правду, и чертовски правильно понять это каким-то тонким способом.И когда вы ошибаетесь, он всегда взрывается во время выполнения.Код отражения компиляция ничего не значит.Он всегда ждет, чтобы вы запустили его, чтобы вырвать перед вашим лицом.

Итак, чтобы ответить на ваш вопрос, не отвечая на него: используйте Карту.Например:

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; }
3 голосов
/ 15 июня 2019

Возможно, вы захотите посмотреть перечисления, если знаете, что они будут постоянными значениями;

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"), но это обычно, если вы читаете из файла конфигурации - в коде вы будете ссылаться на значение напрямую.

2 голосов
/ 15 июня 2019

Когда у вас есть 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 лучше .

...