Java 中的等效名称

nameof equivalent in Java

C# 6.0 引入了 nameof() 运算符,即 returns 一个字符串,代表任何 class / 函数 / 方法 / 局部变量 / 属性 标识符的名称里面。

如果我有这样的class:

class MyClass
{
    public SomeOtherClass MyProperty { get; set; }

    public void MyMethod()
    {
        var aLocalVariable = 12;
    }
}

我可以这样使用运算符:

// with class name:
var s = nameof(MyClass); // s == "MyClass"

// with properties:
var s = nameof(MyClass.OneProperty); // s == "OneProperty"

// with methods:
var s = nameof(MyClass.MyMethod); // s == "MyMethod"

// with local variables:
var s = nameof(aLocalVariable); // s == "aLocalVariable".

这很有用,因为在编译时会检查正确的字符串。如果我拼错了一些property/method/variable的名字,编译器returns就会出错。此外,如果我重构,所有字符串都会自动更新。有关实际用例,请参见示例 this documentation

Java 中是否有任何与该运算符等效的运算符?否则,我怎样才能达到相同(或类似)的结果?

你不能。

您可以使用反射获取方法或字段,但您必须将方法名称硬编码为字符串,这会消除整个目的。

java 没有像 C# 那样内置属性的概念。 getter 和 setter 只是常规方法。您甚至不能像在问题中那样轻松地引用方法。您可以尝试使用反射来获取 getter 方法的句柄,然后切断 get 以获得它相似的 "property" 的名称,但这很丑陋而且不一样。

至于局部变量,根本不可能。

可悲的是,没有这样的事情。前一段时间我一直在寻找这个功能,答案似乎是一般来说,这个东西不存在。

Get name of a field

当然,您可以使用 "Named" 注释来注释您的字段,从而从根本上实现您自己 类 的目标。实际上,有很多框架都依赖于类似的概念。即便如此,这也不是自动的。

你不能。

如果您使用调试符号进行编译,那么 .class 文件将包含 table 个变量名称(这是调试器将变量映射回您的源代码的方式),但不能保证这一点将在那里并且不会在运行时公开。

可以使用运行时字节码检测来完成,例如使用 Byte Buddy 库。

查看此库:https://github.com/strangeway-org/nameof

此处描述了该方法:http://in.relation.to/2016/04/14/emulating-property-literals-with-java-8-method-references/

用法示例:

public class NameOfTest {
    @Test
    public void direct() {
        assertEquals("name", $$(Person.class, Person::getName));
    }

    @Test
    public void properties() {
        assertEquals("summary", Person.$(Person::getSummary));
    }
}

Lombok 有一个实验性功能 @FieldNameConstants

添加注释后,您将获得带有字段名称的内部类型 Fields

@FieldNameConstants
class MyClass {
 String myProperty;
}
...

String s = MyClass.Fields.myProperty; // s == "myProperty"

我也很懊恼Java没有可比性,于是自己实现了:https://github.com/mobiuscode-de/nameof

您可以像这样简单地使用它:

Name.of(MyClass.class, MyClass::getProperty)

这只是 return 字符串

"property"

它也在 上,因此您可以像这样将它添加到您的项目中:

<dependency>
    <groupId>de.mobiuscode.nameof</groupId>
    <artifactId>nameof</artifactId>
    <version>1.0</version>
</dependency>

或 Gradle:

implementation 'de.mobiuscode.nameof:nameof:1.0'

我意识到它与 library from strangeway 非常相似,但我认为最好不要引入奇怪的 $/$$ 符号和增强的字节码工程。我的库只使用代理 class,在其上调用 getter 以确定传递的方法的名称。这允许简单地提取 属性 名称。

我还创建了一个blog post about the library with more details