JDK 7 вводит нового игрока в эту динамическую / динамическую проверку, дескриптор метода (то есть подкласс абстрактного класса java.dyn.MethodHandle). Дескрипторы метода дают нам неограниченные возможности для вызова непубличных методов, например, он может быть сформирован в непубличном методе классом, который может получить к нему доступ. По сравнению с использованием Reflection API проверка доступа выполняется при создании дескриптора метода, а не при каждом вызове метода.
Предположим, у нас есть класс, который должен разрешить контролируемый доступ к одному из его закрытых методов. Ниже приведен класс, определяющий этот метод и описывающий два способа (Reflection / MethodHandle) для доступа к нему.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
public class MethodAccessExampleWithArgs { private final int i; public MethodAccessExampleWithArgs( int i_) { i = i_; } private void bar( int j, String msg) { System.out.println( "Private Method \'bar\' successfully accessed : " + i + ", " + j + " : " + msg + "!" ); } // Using Reflection public static Method makeMethod() { Method meth = null ; try { Class[] argTypes = new Class[] { int . class , String. class }; meth = MethodAccessExampleWithArgs. class .getDeclaredMethod( "bar" , argTypes); meth.setAccessible( true ); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } return meth; } // Using method handles public static MethodHandle makeMh() { MethodHandle mh; MethodType desc = MethodType.methodType( void . class , int . class , String. class ); try { mh = MethodHandles.lookup().findVirtual( MethodAccessExampleWithArgs. class , "bar" , desc); System.out.println( "mh=" + mh); } catch (NoAccessException e) { throw (AssertionError) new AssertionError().initCause(e); } return mh; } } |
Ниже приведен класс, предназначенный для проверки двух подходов к доступу к закрытому методу «bar»:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
public class MethodAccessMain { private static void withReflectionArgs() { Method meth = MethodAccessExampleWithArgs.makeMethod(); MethodAccessExampleWithArgs mh0 = new MethodAccessExampleWithArgs( 0 ); MethodAccessExampleWithArgs mh1 = new MethodAccessExampleWithArgs( 1 ); try { System.out.println( "Invocation using Reflection" ); meth.invoke(mh0, 5 , "Jabba the Hutt" ); meth.invoke(mh1, 7 , "Boba Fett" ); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } private static void withMhArgs() { MethodHandle mh = MethodAccessExampleWithArgs.makeMh(); MethodAccessExampleWithArgs mh0 = new MethodAccessExampleWithArgs( 0 ); MethodAccessExampleWithArgs mh1 = new MethodAccessExampleWithArgs( 1 ); try { System.out.println( "Invocation using Method Handle" ); mh.invokeExact(mh0, 42 , "R2D2" ); mh.invokeExact(mh1, 43 , "C3PO" ); } catch (Throwable e) { e.printStackTrace(); } } public static void main(String[] args) { withReflectionArgs(); withMhArgs(); } } |
Как запустить код — JDK7 b129 и Netbeans 7.0 Beta 2
Приведенный выше код был протестирован со сборкой 129 JDK 7 в среде Netbeans IDE 7.0 Beta 2 и для его работы требовались следующие дополнительные параметры VMO: -XX: + UnlockExperimentalVMOptions -XX: + EnableMethodHandles -XX: + EnableInvokeDynamic в разделе « Выполнить»> > Настройте конфигурацию проекта >> Настройте >> VMoptions , чтобы использовать InvokeDynamic и MethodHandle без получения исключения времени выполнения.
Проблемы с JDK7 b131 и Netbeans 7.0 Beta 2
Если вы обновились до последней сборки — 131 — результат будет зависеть от обстоятельств, при которых вы компилируете и запускаете свой код. Более конкретно, среда IDE NetBans 7.0 Beta 2 выводит следующее:
01
02
03
04
05
06
07
08
09
10
11
12
|
run: Invocation using Reflection Private Method 'bar' successfully accessed : 0, 5 : Jabba the Hutt! Private Method 'bar' successfully accessed : 1, 7 : Boba Fett! java.dyn.WrongMethodTypeException: (ILjava /lang/String ;)V cannot be called as ([Ljava /lang/Object ;)Ljava /lang/Object ; mh=bar(MethodAccessExampleWithArgs,int,String)void Invocation using Method Handle at ben.example.MethodAccessMain.withMhArgs(MethodAccessMain.java:46) at ben.example.MethodAccessMain.main(MethodAccessMain.java:55) BUILD SUCCESSFUL (total time : 0 seconds) |
Проблемы с JDK7 b131 и Eclipse 3.6.2
Этот пример был дополнительно протестирован на Eclipse 3.6.2 Helios с теми же параметрами -XX: + UnlockExperimentalVMOptions -XX: + EnableMethodHandles -XX: + EnableInvokeDynamic, упомянутый в разделе Run >> Run Configurations >> Аргументы >> Аргументы VM , но мы уже обеспечивается идентичный выход.
Из исключения, с которым мы получили запрос, мы видим, что вместо этого наш метод, который должен вызываться с помощью int (I), строки (Ljava / lang / String) и возвращать void (V), вызывается с массив объекта, и возвращает объект. Это показывает, что существуют некоторые проблемы с компилятором, используемым в среде IDE (которые могут отличаться от компилятора командной строки).
Выполнение кода JDK7 b131 в командной строке
Если на вашем компьютере установлена JDK7 после 129 и вы хотите без проблем запустить вышеупомянутые примеры, вам, вероятно, следует придерживаться компиляции (javac) и запуска ( java -XX: + UnlockExperimentalVMOptions -XX: + EnableMethodHandles -XX: + EnableInvokeDynamic com.wgjd.MethodHandleExample.MethodAccessMain ) ваш код MethodHandle из командной строки.
Исправление для JDK7 b131 и IDE
В настоящее время не существует установленной даты, когда мы сможем запускать дескрипторы методов без дополнительных накладных расходов VMOptions, но если вы хотите идти в ногу с последними разработками Da Vinci Machine Project, которые касаются реализации динамического вызова, сделайте уверен, что вы подписались на его список рассылки .
Также стоит упомянуть, что из ранее упомянутого списка рассылки мы обнаруживаем, что есть сложное изменение, которое объединяет код из нескольких пакетов в один пакет и состоит из подготовки к чистому переименованию из java.dyn в java.lang. призывать Это необходимо для исправления некоторых дефектов в API, которые возникают из-за зависимостей между несколькими пакетами.
Рекомендации :
- Взгляд на MethodHandle и его использование от наших партнеров по JCG в Java 7 Developer Blog
- Обоснованный Java-разработчик
Удачного кодирования! Не забудь поделиться!
Byron
Статьи по Теме: