Javareflection:如何获取variables的名称?
使用Javareflection,是否有可能获得本地variables的名称? 例如,如果我有这个:
Foo b = new Foo(); Foo a = new Foo(); Foo r = new Foo();
是否有可能实现一个方法,可以find这些variables的名称,如下所示:
public void baz(Foo... foos) { for (Foo foo: foos) { // Print the name of each foo - b, a, and r System.out.println(***); } }
编辑:这个问题是不同的有没有在Java中find传递给函数的variables的名称的方法? 因为它更纯粹地提出了一个问题:是否可以使用reflection来确定局部variables的名称,而另一个问题(包括被接受的答案)更多地集中在variables的testing值上。
从Java 8开始,通过reflection可以获得一些本地variables名称信息。 请参阅下面的“更新”部分。
完整的信息通常存储在类文件中。 一个编译时优化是删除它,节省空间(并提供一些混淆)。 但是,当它存在时,每个方法都有一个局部variables表属性,它列出局部variables的types和名称以及它们在范围内的指令范围。
也许像ASM这样的字节码工程库可以让你在运行时检查这些信息。 我所能想到的需要这些信息的唯一合理的地方是在开发工具中,所以字节码工程也可能用于其他目的。
更新: Java 8中增加了对此的有限支持。通过reflection现在可以使用参数(一个特殊的局部variables类)名称。 除此之外,这可以帮助replacedependency injection容器使用的@ParameterName
注释。
这是不可能的。 variables名不在Java内传递(也可能由于编译器优化而被删除)。
编辑(相关评论):
如果退一步说,不得不使用它作为函数参数,这里有一个替代scheme(我不会使用 – 见下面):
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
或者有其他字段具有相同的引用a == b, a == r, or b == r
则会出现问题。
编辑现在是不必要的,因为问题得到澄清
( 编辑:先前的两个答案被删除,一个用于回答编辑前的问题,另一个用于如果不是绝对错误的话,至less接近它。 )
如果使用( javac -g
)的debugging信息进行javac -g
,局部variables的名称将保存在.class文件中。 例如,拿这个简单的类:
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
进行编译后,局部variables的名称现在位于.class文件中。 javap
的-l
标志(“打印行号和局部variables表”)可以显示它们。
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; }
VM规范解释了我们在这里看到的:
§4.7.9LocalVariableTable属性 :
LocalVariableTable
属性是Code
(§4.7.3)属性的可选可变长度属性。 debugging器可以使用它来确定在执行方法期间给定局部variables的值。
LocalVariableTable
在每个槽中存储variables的名称和types,所以可以将它们与字节码进行匹配。 debugging器可以执行“评估expression式”。
正如埃里克森所说,虽然没有办法通过正常的反思来访问这张表。 如果你仍然坚持这样做,我相信Java平台debugging器体系结构(JPDA)将有所帮助(但我从来没有用过它)。
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());