Отражение Java: как получить имя переменной?
используя отражение Java, можно ли получить имя локальной переменной? Например, если у меня есть это:
Foo b = new Foo();
Foo a = new Foo();
Foo r = new Foo();
можно ли реализовать метод, который может найти имена этих переменных, например, так:
public void baz(Foo... foos)
{
for (Foo foo: foos) {
// Print the name of each foo - b, a, and r
System.out.println(***);
}
}
EDIT: этот вопрос отличается от того, есть ли способ в Java найти имя переменной, которая была передана функции? в том, что это более чисто задает вопрос о том, можно ли использовать отражение, чтобы определить имя локальная переменная, тогда как другой вопрос (включая принятый ответ) больше ориентирован на тестирование значений переменных.
7 ответов:
начиная с Java 8, некоторая информация об имени локальной переменной доступна через отражение. Смотрите "обновить" ниже.
полная информация часто хранится в файлах классов. Одна оптимизация времени компиляции заключается в ее удалении, экономии места (и обеспечении некоторой обсфускации). Однако, когда он присутствует, каждый метод имеет атрибут таблицы локальных переменных, в котором перечислены тип и имя локальных переменных, а также диапазон инструкций, в которых они находятся масштаб.
возможно, байт-код инженерной библиотеки, как ПКР позволит вам проверить эту информацию во время выполнения. Единственное разумное место, которое я могу придумать для необходимости этой информации,-это инструмент разработки, и поэтому разработка байтового кода, вероятно, будет полезна и для других целей.
обновление: ограниченная поддержка для этого был добавлено в Java 8. параметр (специальный класс локальной переменной) имена теперь доступный через отражение. Среди других целей, это может помочь заменить
@ParameterNameаннотации, используемые контейнерами инъекций зависимостей.
Это не возможно. Имена переменных не передаются в Java (а также могут быть удалены из-за оптимизации компилятора).
редактировать (связанные с комментариями):
Если вы отступите от идеи использовать его в качестве параметров функции, вот альтернатива (которую я бы не использовал-см. ниже):
public void printFieldNames(Object obj, Foo... foos) { List<Foo> fooList = Arrays.asList(foos); for(Field field : obj.getClass().getFields()) { if(fooList.contains(field.get()) { System.out.println(field.getName()); } } }будут проблемы, если
a == b, a == r, or b == rили есть другие поля, которые имеют тот же ссылки на литературу.редактировать теперь не нужно, так как вопрос прояснился
(Edit: два предыдущих ответа удалены, один для ответа на вопрос, как он стоял перед редактированием, и один для того, чтобы быть, если не абсолютно неправильным, по крайней мере, близко к нему.)
если вы компилируете с отладочной информацией на (
javac -g), имена локальных переменных сохраняются в поле .файл класса. Например, возьмем такой простой класс:class TestLocalVarNames { public String aMethod(int arg) { String local1 = "a string"; StringBuilder local2 = new StringBuilder(); return local2.append(local1).append(arg).toString(); } }после компиляции с
javac -g:vars TestLocalVarNames.javaимена локальных переменных сейчас .файл класса.javap' s-lфлаг ("Номер строки печати и таблицы локальных переменных") может показать их.
javap -l -c TestLocalVarNamesпоказывает:class TestLocalVarNames extends java.lang.Object{ TestLocalVarNames(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LTestLocalVarNames; public java.lang.String aMethod(int); Code: 0: ldc #2; //String a string 2: astore_2 3: new #3; //class java/lang/StringBuilder 6: dup 7: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V 10: astore_3 11: aload_3 12: aload_2 13: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 16: iload_1 17: invokevirtual #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 20: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 23: areturn LocalVariableTable: Start Length Slot Name Signature 0 24 0 this LTestLocalVarNames; 0 24 1 arg I 3 21 2 local1 Ljava/lang/String; 11 13 3 local2 Ljava/lang/StringBuilder; }The VM spec объясняет, что мы видим здесь:
§4.7.9 в
LocalVariableTableатрибут:The
LocalVariableTableатрибут является необязательным атрибутом переменной длиныCode(§4.7.3) атрибут. Он может использоваться отладчиками для определения значения заданной локальной переменной во время выполнения a метод.The
архитектура отладчика платформы Java (JPDA) поможет (но я никогда не использовал его сам).LocalVariableTableсохраняет имена и типы переменных в каждом слоте, так что можно сопоставить их с байт-кодом. Вот как отладчики могут сделать "вычислить выражение".
import java.lang.reflect.Field; public class test { public int i = 5; public Integer test = 5; public String omghi = "der"; public static String testStatic = "THIS IS STATIC"; public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException { test t = new test(); for(Field f : t.getClass().getFields()) { System.out.println(f.getGenericType() +" "+f.getName() + " = " + f.get(t)); } } }
вы можете сделать так:
Field[] fields = YourClass.class.getDeclaredFields(); //gives no of fields System.out.println(fields.length); for (Field field : fields) { //gives the names of the fields System.out.println(field.getName()); }
все, что вам нужно сделать, это сделать массив полей, а затем установить его в класс, который вы хотите, как показано ниже.
Field fld[] = (class name).class.getDeclaredFields(); for(Field x : fld) {System.out.println(x);}например, если вы сделали
Field fld[] = Integer.class.getDeclaredFields(); for(Field x : fld) {System.out.println(x);}вы получили бы
public static final int java.lang.Integer.MIN_VALUE public static final int java.lang.Integer.MAX_VALUE public static final java.lang.Class java.lang.Integer.TYPE static final char[] java.lang.Integer.digits static final char[] java.lang.Integer.DigitTens static final char[] java.lang.Integer.DigitOnes static final int[] java.lang.Integer.sizeTable private static java.lang.String java.lang.Integer.integerCacheHighPropValue private final int java.lang.Integer.value public static final int java.lang.Integer.SIZE private static final long java.lang.Integer.serialVersionUID
посмотреть этот пример :
PersonneTest pt=new PersonneTest(); System.out.println(pt.getClass().getDeclaredFields().length); Field[]x=pt.getClass().getDeclaredFields(); System.out.println(x[1].getName());
Comments