Безопасное с точки зрения типов отражение метода в Java

Какой-либо практический путь состоит в том, чтобы сослаться на метод на классе безопасным с точки зрения типов способом? Основной пример - то, если я хотел создать что-то как следующая служебная функция:

public Result validateField(Object data, String fieldName, 
                            ValidationOptions options) { ... }

Для вызова его я должен был бы сделать:

validateField(data, "phoneNumber", options);

Который вынуждает меня или использовать волшебную строку или объявить константу где-нибудь с той строкой.

Я вполне уверен нет никакого способа обойти это с языком Java запаса, но не там некоторый (производственный класс) предварительный компилятор или альтернативный компилятор, который может предложить работу вокруг? (подобный тому, как AspectJ расширяет язык Java) было бы хорошо сделать что-то как следующее вместо этого:

public Result validateField(Object data, Method method, 
                            ValidationOptions options) { ... }

И назовите его с:

validateField(data, Person.phoneNumber.getter, options);
6
задан jthg 5 January 2010 в 22:47
поделиться

3 ответа

Как упоминали другие, нет реального способа сделать это... и я не видел прекомпилятора, который бы поддерживал это. Синтаксис был бы интересен, мягко говоря. Даже в вашем примере он мог бы охватить только небольшое подмножество потенциальных отражающих возможностей, которые может захотеть сделать пользователь, так как он не будет обрабатывать нестандартные аксессуары или методы, которые принимают аргументы и т.д...

Даже если невозможно проверить во время компиляции, если вы хотите, чтобы плохой код как можно быстрее вышел из строя, то один из подходов заключается в разрешении объектов метода, на которые ссылаются во время инициализации класса.

Представьте себе, что у вас есть утилита для поиска объектов Method, которая, возможно, выбрасывает исключение ошибки или время выполнения:

public static Method lookupMethod( Class c, String name, Class... args ) {
    // do the lookup or throw an unchecked exception of some kind with a really
    // good error message
}

Затем в ваших классах, есть константы для преопределения методов, которые вы будете использовать:

public class MyClass {
    private static final Method GET_PHONE_NUM = MyUtils.lookupMethod( PhoneNumber.class, "getPhoneNumber" );

    ....

    public void someMethod() {
        validateField(data, GET_PHONE_NUM, options);
    }
}

По крайней мере, это даст сбой, как только MyClass будет загружен в первый раз.

Я много использую отражение, особенно отражение свойств бобов, и я только что привык к поздним исключениям во время выполнения. Но такой стиль бобового кода имеет тенденцию ошибаться поздно по разным причинам, будучи очень динамичным и все такое. Для чего-то промежуточного помогло бы вышесказанное

.
4
ответ дан 8 December 2019 в 18:37
поделиться

На языке пока ничего нет - но часть предложения по закрытию Java 7 включает буквальные методы, я полагаю.

Боюсь, что у меня нет никаких предложений кроме этого.

3
ответ дан 8 December 2019 в 18:37
поделиться

Есть ли практический способ ссылаться на метод для класса безопасным по типу?

Прежде всего, отражение является безопасным по типу. Просто он динамически набран, а не статически набран.

Таким образом, предполагая, что вы хотите статически набранный эквивалент отражения, теоретический ответ заключается в том, что это невозможно. Рассмотрим следующее:

Method m;
if (arbitraryFunction(obj)) {
    obj.getClass().getDeclaredMethod("foo", ...);
} else {
    obj.getClass().getDeclaredMethod("bar", ...);
}

Можем ли мы сделать это так, чтобы исключение типа исполнения не могло произойти? В общем случае NO, так как это повлечет за собой доказательство того, что произвольнаяFunction(obj) заканчивается. (Это эквивалентно проблеме Хэлтинга, которая в целом доказана неразрешимой и неразрешимой с помощью современной технологии доказательства теорем ... AFAIK.)

И я думаю, что этот дорожный блок применим к любому подходу, где можно ввести произвольный Java код в логику, которая используется для рефлексивного выбора метода из класса объекта.

На мой взгляд, единственным умеренно практичным подходом на данный момент будет замена рефлексивного кода чем-то, что генерирует и компилирует исходный код Java. Если этот процесс происходит до "запуска" приложения, то требование статической типовой безопасности выполнено.


Я больше спрашивал о рефлексии, при которой результат всегда один и тот же. Т.е. Person.class.getMethod("getPhoneNumber", null) всегда возвращал один и тот же метод, и полностью разрешить его можно во время компиляции.

Что произойдет, если после компиляции класса, содержащего этот код, вы измените Person, чтобы удалить метод getPhoneNumber?

Единственный способ убедиться, что вы можете разрешить getPhoneNumber рефлективно, это если вы можете каким-то образом предотвратить Person от изменения. Но вы не можете сделать это на Java. Привязка классов во время выполнения является фундаментальной частью языка.

(Для записи, если бы Вы сделали это для метода, который Вы назвали не отражающим, Вы бы получили IncompatibleClassChangeError какого-нибудь рода при загрузке двух классов ...)

.
1
ответ дан 8 December 2019 в 18:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: