эквивалент nameof в Java

В C# 6.0 появился оператор nameof(), который возвращает строку, представляющую имя любого класса/функции/метода/локальной переменной/идентификатора свойства, помещенного в нее.

Если у меня есть такой класс:

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".

Это полезно, поскольку правильная строка проверяется во время компиляции. Если я неправильно напишу имя какого-либо свойства/метода/переменной, компилятор вернет ошибку. Кроме того, если я рефакторинг, все строки автоматически обновляются. См., например, эту документацию для реальных случаев использования.

Есть ли эквивалент этого оператора в Java? В противном случае, как я могу добиться такого же результата (или подобного)?


person Massimiliano Kraus    schedule 28.11.2016    source источник
comment
Почти уверен, что у Java нет ничего точно эквивалентного. Так что, как и до C# 6, вместо этого вам, скорее всего, придется использовать строковые литералы.   -  person juharr    schedule 28.11.2016
comment
nameof — это синтаксический сахар, добавленный в последнюю версию C# (6). Я почти уверен, что у Java (или большинства популярных языков в целом) не было бы эквивалента.   -  person Abion47    schedule 28.11.2016
comment
Какую проблему вы пытаетесь решить с помощью этой возможности?   -  person OldProgrammer    schedule 28.11.2016
comment
Те же проблемы, которые я решаю с помощью оператора nameof() :)   -  person Massimiliano Kraus    schedule 28.11.2016
comment
Рефлексия ближе всего к этому, но все же не то, что вы ищете, я думаю.   -  person Vucko    schedule 28.11.2016
comment
Я не специалист по С#, но использование nameof() не похоже на чистый дизайн, если это не для ведения журнала и т. д.   -  person f1sh    schedule 28.11.2016
comment
@ f1sh эта функция может быть очень полезна для написания меньшего количества кода и улучшения дизайна. Без него было бы очень сложно и многословно получить тот же результат (через Reflection, например). Прочтите это для более широкого обсуждения.   -  person Massimiliano Kraus    schedule 28.11.2016
comment
@ f1sh Я сам довольно часто использую его для событий с обновлением объектов. Я передаю nameof(AffectedProperty) соответствующему свойству объекта args события, чтобы уведомить слушателей о том, какое свойство было обновлено. Это отличный способ обеспечить безопасность имен свойств во время компиляции.   -  person Abion47    schedule 28.11.2016
comment
@Servy, почему ты удалил тег c#? Я поставил его, потому что функция nameof принадлежит этому языку...   -  person Massimiliano Kraus    schedule 28.11.2016
comment
Вопрос не о C#, а о Java, поэтому этот тег не имеет значения. Он содержит и упоминает C#, но это не гарантирует добавления тега. См. также meta.stackoverflow.com/a/319194/1743880.   -  person Tunaki    schedule 28.11.2016
comment
@Tunaki спасибо за ссылку.   -  person Massimiliano Kraus    schedule 28.11.2016
comment
Кажется, ситуация изменилась, я поделился возможным решением в ответе.   -  person jreznot    schedule 13.08.2018


Ответы (4)


К сожалению, ничего подобного нет. Я искал эту функциональность некоторое время назад, и ответ, казалось, заключался в том, что, вообще говоря, этого материала не существует.

См. раздел Получить имя поля.

Конечно, вы можете аннотировать свое поле аннотацией «Named», чтобы по существу достичь этой цели для своих собственных классов. На самом деле существует большое разнообразие фреймворков, основанных на схожих концепциях. Тем не менее, это не происходит автоматически.

person nasukkin    schedule 28.11.2016
comment
Кажется, что ситуация изменилась с Java 8, я поделился возможным решением ниже. - person jreznot; 18.08.2018

Это можно сделать с помощью инструментария байт-кода во время выполнения, например, с помощью библиотеки Byte Buddy.

См. эту библиотеку: https://github.com/strangeway-org/nameof

Этот подход описан здесь: http://in.relation.to/2016/04/14/emulatory-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));
    }
}
person jreznot    schedule 11.10.2017

Вы не можете.

Вы можете получить метод или поле, используя отражение, но вам придется жестко закодировать имя метода как строку, что устраняет всю цель.

Концепция свойств не встроена в Java, как в C#. Геттеры и сеттеры — это обычные методы. Вы даже не можете ссылаться на метод так же легко, как в своем вопросе. Вы можете попробовать с отражением, чтобы получить дескриптор метода получения, а затем отрезать get, чтобы получить имя «свойства», на которое оно похоже, но это уродливо и не то же самое.

Что касается локальных переменных, то это вообще невозможно.

person f1sh    schedule 28.11.2016
comment
Этот вопрос не имеет ничего общего со свойствами С#. Вопрос заключается в том, можете ли вы получить имя метода или поля, не используя само имя. Ваша точка зрения о том, что для отражения требуется имя для получения метода или поля, уместна. - person Andy Thomas; 28.11.2016
comment
В вопросе очень конкретно упоминаются свойства С#. И я ответил на вопрос нет. Так почему минус? Кроме того, что значит germane? - person f1sh; 28.11.2016
comment
Хорошо, я упомянул свойства C#, но, очевидно, их нет в Java. Это был только пример. Суть моего вопроса в том, чтобы получить строковое представление членов класса/переменных/полей/идентификаторов, и вы ответили некоторыми полезными вещами. - person Massimiliano Kraus; 28.11.2016
comment
@ f1sh - Вы правы - в примере упоминалось свойство. Немецкий значит актуальный. Я отредактировал ваш ответ, чтобы вывести наиболее важные части наверх, и удалил отрицательный голос. Я думаю, что ответ можно улучшить, отметив, что вы можете получить имя класса. - person Andy Thomas; 28.11.2016
comment
Используя отражение, вы можете перечислять методы и свойства и, следовательно, можете обнаруживать имена без их предварительного жесткого кодирования, т.е. .getClass().getDeclaredMethods() и .getClass().getDeclaredFields() - person Stephen P; 01.12.2016
comment
@StephenP Это правда. Но если вы хотите получить имя конкретного, вам придется проверить имя метода/поля с помощью equals или contains, для чего вам нужно снова ввести имя как строковый литерал. - person f1sh; 01.12.2016
comment
@StephenP, который сводит на нет всю цель, если вам все равно нужно будет жестко закодировать имя. - person Orestis P.; 11.08.2019
comment
@ОрестисП. — использование методов, о которых я говорю, может не подходить для этого конкретного вопроса/ситуации, но вам в любом случае не нужно жестко кодировать имя. Имея только ссылку на объект, даже не зная, какой это класс, вы можете использовать самоанализ, чтобы узнать о нем все, что угодно, включая имена классов, методов и полей (и многое другое, чем просто имена). Если вы настаиваете на том, что я ошибаюсь в этом вопросе, что ж, думаю, мне просто нужно выбросить имеющийся у меня рабочий код, который делает именно это. (без жестко закодированных имен) - person Stephen P; 12.08.2019
comment
@StephenP Я не говорю, что вы не можете, я ошибочно подумал, что вы предлагаете рефлексию как потенциальное решение проблемы. - person Orestis P.; 13.08.2019

Вы не можете.

Если вы компилируете с отладочными символами, то файл .class будет содержать таблицу имен переменных (именно так отладчики сопоставляют переменные с вашим исходным кодом), но нет гарантии, что она будет там и не будет отображаться во время выполнения.

person Muhammad Ramzan    schedule 28.11.2016
comment
В вопросе сначала задаются имена классов, методов и полей, которые включены в скомпилированный код и отображаются через отражение. - person Andy Thomas; 28.11.2016
comment
@AndyThomas, нет. Перестаньте минусовать правильные ответы. - person f1sh; 28.11.2016
comment
@f1sh — возвращает строку, представляющую имя члена/класса/поля, помещенного внутрь - person Andy Thomas; 28.11.2016
comment
Вам не нужны символы отладки, чтобы получить имена классов, методов и полей (см. мой комментарий к ответу f1sh). Они нужны вам для получения имен произвольных переменных, объявленных в локальных областях, но это не то, о чем спрашивал ОП. - person Stephen P; 01.12.2016