题主实际想做的是怎样的事情呢?
首先,
以题主的例子:
Object abc = new Object();
这个变量声明,
所以题主真正想问的问题就是:能否获取变量的名字。
如果变量是静态变量或者成员变量(字段),那么它们的名字作为符号信息是一直存在Class文件并带到运行时的。所以在运行时还可以把名字找出来。
但如果题主想做的事情是类似:
nameof(foo.bar); //=> "bar" nameof(this.baz); //=> "baz"
抱歉,Java没有这么方便的功能。
如果变量是参数或局部变量,则其符号信息在正常执行中是不需要的,因而也不会被保留到Class文件里。只有当从Java源码编译到Class文件时指定保留了局部变量的符号信息,才有可能在运行时知道参数或局部变量的名字。
Class文件里有一种属性表叫做
LocalVariableTable,是用来记录参数与局部变量名字的符号信息表。javac编译Java源码时默认不生成这个属性表,只有指定了-g或-g:vars才会生成它。
这个属性表主要用于支持Java的调试器,以便调试器可以把某个slot里的局部变量映射到某个名字上。
一般来说,程序不应该猜测局部变量到底映射到了局部变量区的第几个slot上;但是因为局部变量区的头n个slot是用来存储方法的参数的,参数的位置与名字的映射关系倒是可以很方便的通过LocalVariableTable找出来。
因而这个表也有被调试器之外的程序“滥用”。一个经典的例子就是Spring的
LocalVariableTableParameterNameDiscoverer,传给它一个java.lang.reflect.Method|Constructor,它可以返回一个数组的参数名回来。它就是通过人肉parse出Class文件里的LocalVariableTable来把信息找出来的。
顺带放个传送门:
http://www. valleytalk.org/wp-conte nt/uploads/2011/05/Java_Program_in_Action_20110727.pdf这个场景对LocalVariableTable来说是种“滥用”,所以到Java 8的时候,Class文件格式新增了一个
MethodParameters属性表专门用来存储参数名。这个属性表javac默认不生成,要指定-parameters参数来生成。Java的核心反射API添加了新的java.lang.reflect.Parameter来让代码访问这个属性表的信息。
请参考Obtaining Names of Method Parameters:
https:// docs.oracle.com/javase/ tutorial/reflect/member/methodparameterreflection.html和
JEP 118: Access to Parameter Names at Runtime言归正传,如果有一个局部变量foo,Java里有没有简单的办法可以做到:
nameof(foo); //=> "foo"
呢?
答案是没有。
要nameof()运算符,请用C# 6:
C# - The New and Improved C# 6.0想在Java语言层面添加个nameof()运算符其实不困难,稍微鼓捣下javac就好了。
真有人有需求而且愿意用定制的javac的话我可以写个patch。
但是要说服社区把nameof()运算符加到Java语言规范里就没那么容易了…