Я очень новичок в 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() одинаково хорошо, но безуспешно.
Я сейчас в том, что это, вероятно, «объектные константы»? Я не знаю, как их назвать. Но я определенно не понимаю, как заставить это работать сейчас, и после всего, что я пробовал сам, я решил, что пришло время обратиться за помощью сюда.




Вы можете изучить перечисления, если знаете, что они будут постоянными значениями;
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"), но обычно это происходит, если вы читаете из файла конфигурации — в коде вы бы напрямую ссылались на значение.
Это не сработает, потому что абстрактный класс также имеет методы и переменные, которые не являются постоянными значениями. Кажется, что когда я это делаю, они больше не работают (они становятся неопределенными).
Перечисления Java довольно мощные, вы можете дать им методы, как и другим классам - я обновил ответ примером.
Спасибо, я обязательно еще над этим подумаю. На данный момент принятый ответ работает, и, поскольку я занимался этим всю ночь (сейчас для меня 8 утра), я сначала немного посплю, ха-ха
Когда у вас есть 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 — это лучше.
Кажется, это близко, но как мне превратить f.get(cls) в Enchantment value = ? Когда я попробовал, он сказал мне, что не может преобразовать объект в чары. Я, наверное, действительно новичок здесь, ха-ха
@icecub Видите, это настоящая проблема. Если это Поле В самом деле — Чары, то вам нужен только В ролях. Серьезно, честно: человеку, который не знает, почему и как В ролях объекты java, таким людям не хватает знаний и опыта, чтобы хотя бы приблизиться к рефлексии. Рефлексия — это то, чего даже опытные Java-программисты избегают как чумы. Это никогда не первый правильный вариант, это всегда последнее средство, когда у вас нет другого решения!
@GhostCat Reflection полезно знать (но я согласен, что подход enum здесь лучше).
Извините, мне пришлось сначала провести тестирование, но ваш обновленный ответ работает отлично! Спасибо за терпение. Ты тоже @GhostCat
Этот комментарий уместен: вы, абсолютно, не используете здесь отражение.
Есть только две веские причины для использования отражения:
Но ваш код прекрасно знает об этом классе 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; }
Да, но весь смысл попытки использовать переменную заключается в том, чтобы «преобразовать» значение переменной в имя класса. Если бы я использовал карту, мне нужно было бы объявить, какая строка вызывает какой класс. Я мог бы также просто назвать это напрямую? Возможно, я что-то упускаю из виду, если да, то мой плохой ^^
@icecub Ничто в вашем вопросе не говорило о том, что у вас есть поля типов разные. И когда все о чарах, эта карта или перечисление работают! Дело в том, что Java — это статически компилируемый язык. Вы должны проектировать свое приложение таким образом, чтобы оно соответствовало этой парадигме, вместо того, чтобы пытаться превратить Java в какой-то «какой-то» динамический язык, где вы таким образом переходите от строк к коду. Кроме того, это действительно кричит о проблеме XY. Какую проблему действительный, по вашему мнению, можно решить, имея такие константы, и откуда возникает необходимость называть вещи «из строк»?
Короче сложно объяснить. Я работаю над плагином для сервера Minecraft Bukkit. Сам сервер находится в бета-версии. Таким образом, используя код, предоставленный для получения всех чар, он возвращает только половину из них. Другая половина реализована, просто еще не в «цикле», чтобы вернуться. Я не могу изменить исходный код сервера, потому что плагин не будет работать ни для кого другого, если я это сделаю. Поэтому я должен обойти это и напрямую вызывать реализации из плагина. Я могу сделать это вручную, но с 500+ элементами это было бы безумием. Поэтому вместо этого я пытаюсь напрямую преобразовать пользовательскую команду (строку)