Получить имя поля
Возможно ли в Java получить имя поля в строке из фактического поля? как:
public class mod {
@ItemID
public static ItemLinkTool linkTool;
public void xxx{
String fieldsName = *getFieldsName(linkTool)*;
}
}
PS: Я не ищет имя класса/класс поля или получаю поле от имени в String.
EDIT:
Когда я смотрю на это, мне, вероятно, не понадобится метод для получения имени поля, экземпляра поля (из поля "кодовое имя" ) будет достаточно. [например. Field myField = getField(linkTool)
]
В Java, вероятно, нет ничего подобного. Я посмотрю на библиотеку ASM, но в конце концов я могу использовать строку как идентификатор для полей:/
EDIT2:
Мой английский не велик (но даже на моем родном языке у меня возникнут проблемы с этим объяснением), поэтому я добавляю еще один пример. Hopefuly теперь будет более ясно:
public class mod2 {
@ItemID
public static ItemLinkTool linkTool;
@ItemID
public static ItemLinkTool linkTool2;
@ItemID
public static ItemPipeWrench pipeWrench;
public void constructItems() {
// most trivial way
linkTool = new ItemLinkTool(getId("linkTool"));
linkTool2 = new ItemLinkTool(getId("linkTool2"));
pipeWrench = new ItemPipeWrench(getId("pipeWrench"));
// or when constructItem would directly write into field just
constructItem("linkTool");
constructItem("linkTool2");
constructItem("pipeWrench");
// but I'd like to be able to have it like this
constructItemIdeal(linkTool);
constructItemIdeal(linkTool2);
constructItemIdeal(pipeWrench);
}
// not tested, just example of how I see it
private void constructItem(String name){
Field f = getClass().getField(name);
int id = getId(name);
// this could be rewritten if constructors take same parameters
// to create a new instance using reflection
if (f.getDeclaringClass() == ItemLinkTool){
f.set(null, new ItemLinkTool(id));
}else{
f.set(null, new ItemPipeWrench(id));
}
}
}
Возникает вопрос: как посмотреть метод constructItemIdeal? (Из ответов и googling вокруг я ничего не могу в Java, но кто знает..)
Ответы
Ответ 1
К сожалению, нет способа сделать то, что вы пожелаете. Почему?
В эпоху, когда мы все еще пытаемся доказать, что Java не медленна, хранение метаданных о том, где и как был создан объект, будет иметь большие накладные расходы, и поскольку он имеет очень минимальный диапазон использования, он не существует, Не только это: есть множество технических причин.
Одна из причин связана с тем, как реализуется JVM. Спецификацию формата файла Java class
можно найти здесь здесь. Это довольно много, но очень информативно.
Как я уже говорил ранее, объект может быть построен из любого места, даже в ситуациях, когда объекты не имеют имен. Только объекты, определенные как члены класса, имеют имена (по очевидной причине доступа): объектов, построенных в методах, нет. JVM имеет локальную таблицу переменных с максимальным количеством 65535 записей. Они загружаются в стек и сохраняются в таблице с помощью кодов операций * load и * store.
Другими словами, класс, подобный
public class Test {
int class_member = 42;
public Test() {
int my_local_field = 42;
}
}
скомпилируется в
public class Test extends java.lang.Object
SourceFile: "Test.java"
minor version: 0
major version: 50
Constant pool:
--snip--
{
int class_member;
public Test();
Code:
Stack=2, Locals=2, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 42
7: putfield #2; //Field class_member:I
10: bipush 42
12: istore_1
13: return
LineNumberTable:
--snip--
}
Здесь вы можете увидеть ясный пример из javap -v Test
, что, хотя имя class_member
сохраняется, my_local_field
было абстрагировано до индекса 1 в локальной таблице переменных (0 зарезервировано для this
).
Это само по себе было бы болью для отладчиков и тому подобное, поэтому был разработан набор атрибутов (думаю, метаданные для файлов классов). К ним относятся LocalVariableTable, LineNumberTable и LocalVariableTypeTable. Эти атрибуты полезны для stacktraces (LineNumberTable) и отладчиков (LocalVariableTable и LocalVariableTypeTable). Тем не менее, они полностью необязательны для включения в файлы, и нет никакой гарантии, что они:
Атрибут LineNumberTable является необязательным атрибутом переменной длины в таблице атрибутов
То же самое верно для остальных.
Кроме того, большинство компиляторов по умолчанию не производят ничего, кроме LineNumberTable, поэтому вам было бы не повезло, даже если бы это было возможно.
В принципе, разработчикам было бы очень неприятно иметь getFieldName(object)
(что было бы невозможно в первую очередь для локальных переменных) и работать с ними только тогда, когда эти атрибуты присутствуют.
Итак, вы застряли в обозримом будущем с помощью getField
со строками. Бесстыдная плагин: IntelliJ, похоже, хорошо справляется с рефакторами с отражением: написав мотивы Minecraft, я знаю это чувство и могу сказать, что работа по рефакторингу значительно сокращается IntelliJ. Но то же самое, вероятно, верно для большинства современных IDE: я уверен, что крупные игроки, Eclipse, Netbeans и др. имеют хорошо реализованные системы рефакторинга.
Ответ 2
Это возможно только через отражение.
Используйте Class.getDeclaringFields
()
и java.reflection.Field.getName()
Ответ 3
Если поле является приватным, вы можете сделать его доступным:
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
String value = (String)field.get(object); // to get the value, if needed. In the example is string type
Чтобы получить имя поля, сделайте следующее:
//use the field object from the example above
field.getName(); // it is in String.
Если вы не знаете название поля... ну... тогда какое поле вы хотели бы получить?:) Вы можете получить ВСЕ поля, используя отражение, а затем прокрутите их. Но если вы не знаете поле, каков фактический смысл и логика в этом действии?
Ответ 4
Строковое полеName = getFieldName (linkTool, this);
private static String getFieldName(Object fieldObject, Object parent) {
java.lang.reflect.Field[] allFields = parent.getClass().getFields();
for (java.lang.reflect.Field field : allFields) {
Object currentFieldObject;
try {
currentFieldObject = field.get(parent);
} catch (Exception e) {
return null;
}
boolean isWantedField = fieldObject.equals(currentFieldObject);
if (isWantedField) {
String fieldName = field.getName();
return fieldName;
}
}
return null;
}
Ответ 5
Моя мотивация при получении имени поля использует его для поиска вещей в базе данных с ключом (например, mongodb). У меня есть структура с членами (полями), которые представляют сохраненные данные. Я использую имена членов для поиска db.
Мое предложение - поставить статический геттер для каждого важного члена. Пример:
public class Data {
public static String getMember1Key() {
return "member1";
}
public String member1;
}
Надеюсь, Java будет иметь некоторый механизм для этого в будущем, потому что в настоящее время метаданные могут быть частью данных. Особенно при работе с JSON.
Ответ 6
Это можно сделать с помощью инструментария байтового кода времени выполнения, например, используя библиотеку Byte Buddy, см. этот ответ имя эквивалента в Java