una - obtener nombre de imagen java
Reflexión de Java: ¿cómo obtener el nombre de una variable? (7)
Usando Java Reflection, ¿es posible obtener el nombre de una variable local? Por ejemplo, si tengo esto:
Foo b = new Foo();
Foo a = new Foo();
Foo r = new Foo();
¿Es posible implementar un método que pueda encontrar los nombres de esas variables, así:
public void baz(Foo... foos)
{
for (Foo foo: foos) {
// Print the name of each foo - b, a, and r
System.out.println(***);
}
}
EDITAR: Esta pregunta es diferente de ¿Hay alguna forma en Java para encontrar el nombre de la variable que se pasó a una función? en que pregunta de manera más pura si se puede utilizar la reflexión para determinar el nombre de una variable local, mientras que la otra pregunta (incluida la respuesta aceptada) se centra más en probar los valores de las variables.
( Editar: se eliminaron dos respuestas anteriores, una para responder a la pregunta tal como estaba antes de las ediciones y una para ser, si no absolutamente incorrecta, al menos cercana a ella ) .
Si compila con información de depuración en ( javac -g
), los nombres de las variables locales se mantienen en el archivo .class. Por ejemplo, toma esta clase simple:
class TestLocalVarNames {
public String aMethod(int arg) {
String local1 = "a string";
StringBuilder local2 = new StringBuilder();
return local2.append(local1).append(arg).toString();
}
}
Después de compilar con javac -g:vars TestLocalVarNames.java
, los nombres de las variables locales ahora están en el archivo .class. El indicador javap
''s -l
("Número de línea de impresión y tablas de variables locales") puede mostrarlos.
javap -l -c TestLocalVarNames
muestra:
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;
}
La especificación de VM explica lo que estamos viendo aquí:
§4.7.9 El atributo LocalVariableTable
:
El atributo
LocalVariableTable
es un atributo opcional de longitud variable de un atributo deCode
(§4.7.3). Puede ser utilizado por los depuradores para determinar el valor de una variable local dada durante la ejecución de un método.
LocalVariableTable
almacena los nombres y tipos de las variables en cada ranura, por lo que es posible hacer coincidirlos con el bytecode. Así es como los depuradores pueden hacer "Evaluar expresión".
Sin embargo, como dijo Erickson, no hay forma de acceder a esta mesa a través de la reflexión normal. Si todavía está decidido a hacer esto, creo que la Java Platform Debugger Architecture (JPDA) ayudará (pero nunca la he usado).
A partir de Java 8, parte de la información del nombre de variable local está disponible a través de la reflexión. Vea la sección "Actualizar" a continuación.
La información completa a menudo se almacena en archivos de clase. Una optimización en tiempo de compilación es eliminarlo, ahorrando espacio (y proporcionando cierta obstrucción). Sin embargo, cuando está presente, cada método tiene un atributo de tabla variable local que enumera el tipo y el nombre de las variables locales, y el rango de instrucciones en el que están dentro del alcance.
Quizás una biblioteca de ingeniería de código de bytes como ASM le permita inspeccionar esta información en tiempo de ejecución. El único lugar razonable en el que puedo pensar para necesitar esta información es en una herramienta de desarrollo, por lo que la ingeniería de código byte también puede ser útil para otros fines.
Actualización: Se agregó soporte limitado para esto a Java 8. Los nombres de parámetros (una clase especial de variable local) ahora están disponibles a través de la reflexión. Entre otros fines, esto puede ayudar a reemplazar @ParameterName
anotaciones @ParameterName
utilizadas por los contenedores de inyección de dependencias.
No es posible en absoluto. Los nombres de las variables no se comunican dentro de Java (y también pueden eliminarse debido a las optimizaciones del compilador).
EDITAR (relacionado con los comentarios):
Si se aleja de la idea de tener que usarlo como parámetros de función, aquí hay una alternativa (que no usaría - vea abajo):
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());
}
}
}
Habrá problemas si a == b, a == r, or b == r
o hay otros campos que tienen las mismas referencias.
EDITAR ahora innecesario ya que la pregunta fue aclarada
Puedes hacer así:
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());
}
Todo lo que necesita hacer es crear una matriz de campos y luego configurarla en la clase que desee, como se muestra a continuación.
Field fld[] = (class name).class.getDeclaredFields();
for(Field x : fld)
{System.out.println(x);}
Por ejemplo, si lo hiciste
Field fld[] = Integer.class.getDeclaredFields();
for(Field x : fld)
{System.out.println(x);}
obtendrías
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
mira este ejemplo:
PersonneTest pt=new PersonneTest();
System.out.println(pt.getClass().getDeclaredFields().length);
Field[]x=pt.getClass().getDeclaredFields();
System.out.println(x[1].getName());
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));
}
}
}