Подтвердить что ты не робот

Получить имя поля

Возможно ли в 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, но кто знает..)

4b9b3361

Ответ 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