Статьи

Взгляд на MethodHandle и его использование

Благодаря Java Reflection API мы смогли проверить и изменить выполнение программы во время выполнения. В частности, мы можем наблюдать интерфейсы / классы / методы и поля во время выполнения, не зная их имен во время компиляции.

JDK 7 вводит нового игрока в эту динамическую / динамическую проверку, дескриптор метода (то есть подкласс абстрактного класса  java.dyn.MethodHandle). Дескрипторы метода дают нам неограниченные возможности для вызова непубличных методов, например, он может быть сформирован в непубличном методе классом, который может получить к нему доступ. По сравнению с использованием Reflection API проверка доступа выполняется при создании дескриптора метода, а не при каждом вызове метода.

Предположим, у нас есть класс, который должен разрешить контролируемый доступ к одному из его закрытых методов. Ниже приведен класс, определяющий этот метод и описывающий два способа (Reflection / MethodHandle) для доступа к нему.

 

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»:

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 выводит следующее:

 

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. Invoke . Это необходимо для исправления некоторых дефектов в API, которые возникают из-за зависимостей между несколькими пакетами.  

MethodHandles покрыты в полном объеме в нашем Колодец заземленной разработчиков Java титул  

С http://www.java7developer.com/blog/?p=191