Java Reflection:如何获取变量的名称?

2022-08-31 07:24:58

使用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(***); 
    }
}

编辑:这个问题与Java中是否有办法找到传递给函数的变量的名称不同?因为它更纯粹地询问是否可以使用反射来确定局部变量的名称,而另一个问题(包括接受的答案)更侧重于变量的测试值。


答案 1

从 Java 8 开始,一些局部变量名称信息可以通过反射获得。请参阅下面的“更新”部分。

完整的信息通常存储在类文件中。一种编译时优化是删除它,从而节省空间(并提供一些混淆)。但是,当它存在时,每个方法都有一个局部变量表属性,该属性列出了局部变量的类型和名称,以及它们在作用域中的指令范围。

也许像ASM这样的字节码工程库将允许您在运行时检查此信息。我能想到的需要这些信息的唯一合理的地方是在开发工具中,因此字节码工程也可能用于其他目的。


更新:对此的有限支持已添加到 Java 8 中。参数(局部变量的特殊类)名称现在可通过反射获得。除其他用途外,这可以帮助替换依赖项注入容器使用的注释。@ParameterName


答案 2

这根本不可能。变量名称不会在 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

编辑现在没有必要,因为问题得到了澄清