Есть ли способ в Java найти имя переменной, которая была передана функции?
Я использую его для проверки нескольких объектов, чтобы убедиться, что они не равны нулю. Но я не могу назвать имя переменной таким образом.
testForNull(x); testForNull(y); testForNull(z);
Я не могу определить, какая из трех строк вызвала вывод “Object is null”. Конечно, я могу просто добавить еще один параметр в функцию и иметь что-то вроде
testForNull(x, "x"); testForNull(y, "y"); testForNull(z, "z");
Но я хочу знать, можно ли вывести имя переменной, не передавая ее явно. Благодарю.
Учтите, что параметр не мог быть переменной (и поэтому не имел бы имени):
Нет, такого пути нет. Вам нужно будет явно передать имя переменной.
Однако, если ваш объект имеет поле “имя” или отображает его имя с помощью функции toString() , это может вам помочь.
Для этого нужен отладчик. Невозможно сделать это программно. Что делать, если я вызываю testForNull(1 + 1) . Что такое имя переменной?
Eclipse имеет графический и простой в использовании отладчик для встроенного Java. Изучение того, как использовать это, принесет дивиденды в долгосрочной перспективе, и это будет немедленное решение вашей проблемы.
вы можете поместить вызов метода в foreach и установить идентификатор ссылки для каждого объекта, через который вы проходите, даже если он возвращает null или не null для этого конкретного объекта.
Да, но я бы не рекомендовал его, и это было бы исключительно сложно. Вместо этого попробуйте assert :
Чтобы сделать то, что вы хотите, если у вас есть исходный код, получите текущий поток http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#currentThread()
Получить второй-последний элемент, имя класса, имя файла и номер строки, затем распечатать эту строку или проанализировать ее http://docs.oracle.com/javase/7/docs/api/java/lang/StackTraceElement.html#method_summary
Ба, Посмотрев на исходный вопрос снова, это не стартер.
Вопрос требует, чтобы мы могли предоставить средство, с помощью которого значение, переданное в метод CheckForNull(), может получить имя значений – и здесь кикер… только тогда, когда значение равно null.
Нет абсолютно никакого способа получить что-либо от нулевого значения, отличного от String, содержащего “null” или исключение NullPointerException.
Но, как обычно, ориентация объекта на спасение. Создайте класс значений, как я упоминал выше. Теперь добавьте к нему метод isNull(). Используйте этот класс значений для любого значения, которое вы хотите сбросить отладочный текст.
Java – это объектно-ориентированный язык, поэтому ответ “определенно!” вы можете указать имя переменной, переданной в качестве параметра. Для этого попробуйте это…
class Value extends Object < T value; String name; public Value(String name, T value) < this.name = name; this.value = value; >>
Теперь в ваших методах вы принимаете все параметры как экземпляры Value, как в следующем методе, который принимает только значения, созданные с классами, имеющими Number в качестве базового класса (который будет Long, Float, Double и т.д.)…
public String SomeMethodWantingToKnowParameterNames(Value parm1) < if (parm1 != null) < // Do your work with the parameter - it name can be accessed via parm1.name // This is only an example // You would probably want to write an accessor for name return parm1.name; >// Return null for null return null; >
И это все, что есть! Я использую общий класс, чтобы значение могло использоваться для передачи в любом виде – Floats, Longs, Double, BigInteger, String – например…
Value vFloat = new Value("MyFloat", 0.0);
Кроме того, приведенный выше метод является просто примером – на практике любой метод, принимающий значение, может получить доступ к его имени.
Удачи, и ваш код легко компилируется!
Как вывести имя переменной, переданной в метод
Как узнать имя переданной в запросе переменной?
Как узнать имя переданной в запросе переменной? То есть известно значение переменной, а имя было.
Присвоить переменной «x» имя цифры, переданной из переменной «a»
Задача такая! В этой задаче вам нужно записать в указанном месте код, который присваивает.
Как передать в метод не значение, а имя переменной?
Есть некий метод: Method1(string Name, string Value) Метод вписывает в указанную строку (string.
Вот пример кода, где в методе -moveListItem- мне нужно через println выводить какой именно ArrayList был загружен в текущем потоке:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class LockUnlock { public static void main(String[] args) { ListInteger> list1 = new ArrayList<>(Arrays.asList(2, 4, 6, 8)); ListInteger> list2 = new ArrayList<>(Arrays.asList(1, 3, 5, 7)); ReentrantLock lockList1 = new ReentrantLock(); ReentrantLock lockList2 = new ReentrantLock(); Thread thread1 = new Thread(() -> { moveListItem(list1, list2, 2, lockList1, lockList2); }); Thread thread2 = new Thread(() -> { moveListItem(list2, list1, 1, lockList2, lockList1); }); thread1.start(); thread2.start(); try { thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } try { thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list1); System.out.println(list2); } private static void moveListItem(ListInteger> fromList, ListInteger> toList, int item, ReentrantLock lock1, ReentrantLock lock2) { try { System.out.println(Thread.currentThread().getName() + " trying to lock -fromList-."); if(lock1.tryLock(1, TimeUnit.SECONDS)){ System.out.println(Thread.currentThread().getName() + " locked -fromList-."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Thread.yield(); try { System.out.println(Thread.currentThread().getName() + " trying to lock -toList-."); if(lock2.tryLock(1, TimeUnit.SECONDS)){ System.out.println(Thread.currentThread().getName() + " locked -toList-."); if (fromList.contains(item)) { fromList.remove(item); toList.add(item); } lock2.unlock(); System.out.println(Thread.currentThread().getName() + " unlock -toList-."); } else { System.out.println(Thread.currentThread().getName() + " cant lock -toList-."); } } catch (InterruptedException e) { e.printStackTrace(); } lock1.unlock(); System.out.println(Thread.currentThread().getName() + " unlock -fromList-."); } else { System.out.println(Thread.currentThread().getName() + " cant lock -fromList-."); } } catch (InterruptedException e) { e.printStackTrace(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
public class Cyber { static class LikeInteger { String name; int val; LikeInteger(String name, int val) { this.name = name; this.val = val; } public String getName() { return name; } public int getVal() { return val; } } public static void main(String[] args) { LikeInteger a = new LikeInteger("a",3); printName(a); } private static void printName(LikeInteger a1) { System.out.printf("Name of first parameter is %s, and value = %d", a1.getName(), a1.getVal()); } }
Отражение Java: Как получить имя переменной?
Используя Java Reflection, можно ли получить имя локальной переменной? Например, если у меня есть это:
Foo b = new Foo(); Foo a = new Foo(); Foo r = new Foo();
EDIT: этот вопрос отличается от Есть ли способ в Java найти имя переменной, которая была передана функции?, поскольку она более просто запрашивает вопрос о том, можно ли использовать отражение для определения имени локальной переменной, тогда как другой вопрос (включая принятый ответ) более сфокусирован на тестировании значений переменных.
Все отличные ответы! Спасибо всем за ответы и комментарии — это было интересное и проницательное обсуждение.
Не дубликат, и обновил мой вопрос, чтобы объяснить, почему. Во всяком случае, этот другой вопрос является дубликатом (или особым случаем) этого вопроса!
7 ответов
Как и в случае с Java 8, некоторые локальные данные с именами переменных доступны через отражение. См. Раздел «Обновление» ниже.
Полная информация часто хранится в файлах классов. Одна оптимизация времени компиляции — это удаление, экономия места (и предоставление некоторой обфускации). Однако, когда он присутствует, каждый метод имеет атрибут таблицы локальной переменной, который перечисляет тип и имя локальных переменных и диапазон инструкций, где они находятся в области.
Возможно, техническая библиотека байт-кода, такая как ASM, позволит вам проверять эту информацию во время выполнения. Единственное разумное место, которое я могу придумать для получения этой информации, — это инструмент разработки, поэтому разработка байтового кода, вероятно, будет полезна и для других целей.
Обновление: ограниченная поддержка для этого была добавлена в Java 8. Теперь параметры параметров (специальный класс локальной переменной) теперь доступны через отражение. Среди других целей это может помочь заменить аннотации @ParameterName , используемые контейнерами для инъекций зависимостей.
Это невозможно. Имена переменных не передаются в Java (а также могут быть удалены из-за оптимизации компилятора).
EDIT (связанный с комментариями):
Если вы отступите от идеи использовать его в качестве параметров функции, вот альтернатива (которую я бы не использовал — см. ниже):
public void printFieldNames(Object obj, Foo. foos) < ListfooList = 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 или есть другие поля, которые имеют одинаковые ссылки.
РЕДАКТИРОВАТЬ теперь не нужно, так как вопрос выяснился
-1: я думаю, что вы не поняли. @David — после полей, а не локальных переменных. Локальные переменные действительно недоступны через Reflection API.
Я думаю, что Pourquoi Litytestdata прав. Очевидно, что поля нельзя оптимизировать, поэтому Марсель Дж. Должен думать о локальных переменных.
@David: Дэвид: Вам нужно отредактировать, чтобы уточнить, что вы имели в виду поля, а не локальные переменные. Исходный вопрос дает код, который объявляет b, a и r в качестве локальных переменных.
пожалуйста, не наказывайте кого-то за то, что он не читает мысли, когда оригинальный постер означал одно, а спрашивал что-то другое. 🙁
Я согласен, что он говорил о полях, но метод, который он приводит в качестве примера, ясно заявляет, что он будет использовать их в качестве параметров, как в baz(b,a,r); что просто не сработает.
@Jason Джейсон С .: Он сказал и «переменная экземпляра», и «поле». Эти объявления могут быть локальными переменными, или они могут быть частными полями пакета, или он мог создавать их на месте и просто забывать модификаторы доступа. Они не противоречат непосредственно заданному вопросу.
Я имел в виду локальные переменные, и я отредактировал вопрос, чтобы отразить это. Я думал, что невозможно получить имена переменных, но я решил спросить SO, прежде чем считать это невозможным.
(Edit: удалены два предыдущих ответа, один для ответа на вопрос, когда он стоял перед редактированием, и один для того, чтобы быть, если не совсем ошибочным, по крайней мере близко к нему.)
Если вы компилируете информацию об отладке ( javac -g ), имена локальных переменных хранятся в файле .class. Например, возьмите этот простой класс:
После компиляции с javac -g:vars TestLocalVarNames.java имена локальных переменных теперь находятся в файле .class. javap -l ( «Номер строки печати и таблицы локальных переменных» ) может показать их.
javap -l -c TestLocalVarNames показывает:
class TestLocalVarNames extends java.lang.Object< TestLocalVarNames(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()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."":()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; >
спецификация VM объясняет, что мы видим здесь:
Атрибут LocalVariableTable является необязательным атрибутом переменной длины атрибута Code (§4.7.3). Он может использоваться отладчиками для определения значения данной локальной переменной во время выполнения метода.
В LocalVariableTable хранятся имена и типы переменных в каждом слоте, поэтому их можно сопоставить с байт-кодом. Именно так отладчики могут выполнять «Оценка выражения».
Как сказал Эриксон, нет никакого способа получить доступ к этой таблице через нормальное отражение. Если вы все еще решите сделать это, я полагаю, что Java Debugger Architecture (JPDA) поможет (но я никогда не использовал его сам).