Comments 14
Видел подобные тесты, которые показывают, что т.н. новый "reflection API" в Java 8 и выше, довольно быстр, что не может не радовать. Но MethodHandle (конкретно в Oracle JDK 8 build 65) вызывал у нас в проекте ошибку OutOfMemory, аналогично ситуации, описанной здесь: https://bugs.openjdk.java.net/browse/JDK-7021343.
Пришлось отказаться от его использования.
Странно всё это. Ошибка по ссылке чисто техническая: возвращается одна ошибка вместо другой, в любом случае сценарий использования неадекватный. Вероятно, у вас ошибка по какому-то другому поводу, не связанная с этим багом. Вообще если вы используете лямбды, вы уже используете методхэндлы.
MethodHandle.invoke
, хоть и реализован по-другому, но делает примерно всё то же, что и Method.invoke
, за исключением проверок доступа. Поэтому большого выигрыша сами по себе MethodHandles не дают. Чтобы получить максимальную выгоду от java.lang.invoke
, имеет смысл MethodHandle преобразовать в экземпляр интерфейса с помощью LambdaMetafactory. И тогда вызов будет столь же быстрым, как и обычный invokeinterface
.реализация на стороне C++ тривиальнаОй ли? :)
Вся сложность нативной рефлексии скрыта именно внутри JVM кода, чему посвящён целый класс на 1000+ строк кода. Здесь и ресолвинг метода, и преобразование типов, и всевозможные проверки, и перекладывание аргументов. И всё это интерпретируется каждый раз заново для каждого вызова, на что как раз и тратится уйма времени.
А что будет в генерированном классе если вызываемый через рефлекшн метод бросает interrupted exception?
Хотя какая разница. Клиент должен это хэндлить.
Если нет необходимости, конечно, лучше избегать. Хотя бы ради читаемости кода. Всяко же лучше p.getName()
, чем Person.class.getMethod("getName").invoke(p)
? :-)
С восьмой джавы некоторые сценарии динамического вызова с рефлекшном можно заменить на ссылки на методы. Скажем, раньше вы куда-то передавали класс и имя метода, который вам должен что-то возвращать: doSomething(Person.class, "getName")
и внутри делали вот это всё clazz.getMethod
. Теперь это можно заменить на doSomething(Person::getName)
(тип аргумента Supplier<String>
). Это сделает код более читаемым и быстрым.
Вызов методов через reflection