小编典典

有关MethodHandle API的一些基本问题

java

我如何通过获得所有声明的方法MethodHandles.lookup()?如何获取所有声明的字段?

有什么区别MethodHandle.invoke()MethodHandle.invokeExact()MethodHandle.invokeWithArguments()

另外,对于使用MethodHandle API for Java devloper的
教程,我将不胜感激。我强调,我是在使用静态类型语言的普通Java上编程的,并且我不是JVM开发人员,尤其是我对整个字节码废话(invokedynamic)不感兴趣。我想弄清楚如何使用此新API代替Java
Core API。

编辑2:

下面的@Glen Best提供了一些参考,我只想提供一个http://www.oraclejavamagazine-
digital.com/javamagazine/20130102?pg=52&search_term=methodhandle&doc_id=-1#pg50这正是我在寻找的东西。我发现实际上存在一些新词汇。例如,
目标 实际上是MethodHandle(而不是要进行分派的对象),而 调用站点
实际上是“调用”“函数指针”(又称为MethodHandle)的代码。此外,它是一定要了解MethodHandle API是 不是更换为
核心映像API,而不是 suplement 它。例如,您不能使用需要Core Reflection
API的MethodHandle来“发现”所有方法。但是,当您“查找”所需的方法时,可以切换到MethodHandle,例如,将其某些参数绑定或将其签名“更改”(适应)到varargs。

编辑:

我仍在尝试找出答案。我写了一些我想与所有人共享的测试。

package alexander.berkovich;

import static org.junit.Assert.assertSame;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.junit.BeforeClass;
import org.junit.Test;

public class MethodHandlerCleanTest {

    public static MethodHandles.Lookup lookup;

    @BeforeClass
    public static void asetUp(){
        lookup = MethodHandles.lookup();
    }

    public static class Check {
        public void primitive(final int i){
        }
        public void wrapper(final Integer i){
        }
    }

    @Test
    public void testPrimitive() throws Throwable {
        Check check = new Check();

        MethodType type = MethodType.methodType(void.class, int.class);

        MethodHandle mh = lookup.findVirtual(Check.class, "primitive", type);
        mh.invokeWithArguments(check, 1);
        mh.invoke(check, (short)2);
        mh.invoke(check, Integer.valueOf(3));

        Method method = Check.class.getMethod("primitive", int.class);
        method.invoke(check, (short)20);
        method.invoke(check, Integer.valueOf(21));

    }

    @Test
    public void testWrapper() throws Throwable {
        Check check = new Check();

        MethodType type = MethodType.methodType(void.class, Integer.class);

        MethodHandle mh = lookup.findVirtual(Check.class, "wrapper", type);
        mh.invoke(check, 2);

        Method method = Check.class.getMethod("wrapper", Integer.class);
        method.invoke(check, 20);

    }

    @SuppressWarnings("unused")
    public static class StaticInnerClass {

        public static String staticName;
        public String name;


        public void foo(){}

        public static void staticFoo(){}

    }

    @Test
    public void testStaticInnerClassStaticField() throws Throwable {
        MethodHandle mhSet = lookup.findStaticSetter(StaticInnerClass.class, "staticName", String.class);
        String expected = "mama";
        mhSet.invoke(expected);

        MethodHandle mhGet = lookup.findStaticGetter(StaticInnerClass.class, "staticName", String.class);
        Object obj = mhGet.invoke();
        String value = (String)obj;
        assertSame(expected, value);

    }

    @Test
    public void testStaticInnerClassField() throws Throwable {
        StaticInnerClass sut = new StaticInnerClass();
        Field f = StaticInnerClass.class.getDeclaredField("name");
        MethodHandle mhSetUnreflect = lookup.unreflectSetter(f); 
        String expectedUnreflect = "unreflect";
        mhSetUnreflect.invoke(sut, expectedUnreflect);


        MethodHandle mhSet = lookup.findSetter(StaticInnerClass.class, "name", String.class);
        String expected = "mama";
        mhSet.invoke(sut, expected);

        MethodHandle mhGet = lookup.findGetter(StaticInnerClass.class, "name", String.class);
        Object obj = mhGet.invoke(sut);
        String value = (String)obj;
        assertSame(expected, value);

    }

    @Test
    public void testStaticInnerClassConstructor() throws Throwable {
        StaticInnerClass sut = new StaticInnerClass();
        MethodType type = MethodType.methodType(void.class);
        MethodHandle mh = lookup.findConstructor(StaticInnerClass.class, type);
        mh.invoke();
    }

    @Test
    public void testStaticInnerClassMethod() throws Throwable {
        StaticInnerClass sut = new StaticInnerClass();
        MethodType type = MethodType.methodType(void.class);
        MethodHandle mh = lookup.findVirtual(StaticInnerClass.class, "foo", type);
        mh.invoke(sut);
    }

    @Test
    public void testStaticInnerClassStaticMethod() throws Throwable {
        MethodType type = MethodType.methodType(void.class);
        MethodHandle mh = lookup.findStatic(StaticInnerClass.class, "staticFoo", type);
        mh.invoke();
    }

    @SuppressWarnings("unused")
    private class InnerClass {
        public String name;

        public void foo(){}

    }
    @Test
    public void testInnerClassField() throws Throwable {
        InnerClass sut = new InnerClass();
        MethodHandle mhSet = lookup.findSetter(InnerClass.class, "name", String.class);
        String expected = "mama";
        mhSet.invoke(sut, expected);

        MethodHandle mhGet = lookup.findGetter(InnerClass.class, "name", String.class);
        Object obj = mhGet.invoke(sut);
        String value = (String)obj;
        assertSame(expected, value);

    }


    @Test
    public void testInnerClassConstructor() throws Throwable {
        MethodType type = MethodType.methodType(void.class, MethodHandlerCleanTest.class);

        //default constructor is private
        Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
        field.setAccessible(true);
        MethodHandles.Lookup trustedLookup = (MethodHandles.Lookup) 
                field
                .get(null);

        MethodHandle mh = trustedLookup.findConstructor(InnerClass.class, type);
        mh.invoke(this);
    }


    @Test
    public void testInnerClassMethod() throws Throwable {
        InnerClass sut = new InnerClass();
        MethodType type = MethodType.methodType(void.class);
        MethodHandle mh = lookup.findVirtual(InnerClass.class, "foo", type);
        mh.invoke(sut);
    }

}


阅读 214

收藏
2020-10-18

共1个答案

小编典典

如何通过MethodHandles.lookup()获取所有声明的方法? 如何获取所有声明的字段?

将java.lang.invoke视为反射(java.lang.reflect)的(快速执行)扩展-即“ invoke”类依赖于“
reflection”类。

  • 您可以通过反射(java.lang.Class和java.lang.reflect)获得对所有方法/构造函数/字段的引用:
        java.lang.Class<?> someClass = ...;  // obtain a Class somehow

    // Returns all constructors/methods/fields declared in class, 
    // whether public/protected/package/private, 
    // but does NOT include definitions from any ancestors:

    java.lang.reflect.Constructor<?>[] declaredConstructors = someClass.getDeclaredConstructors();
    java.lang.reflect.Method[] declaredMethods = someClass.getDeclaredMethods();
    java.lang.reflect.Field[] declaredFields   = someClass.getDeclaredFields();

    // Returns all constructors/methods/fields declared as public members 
    // in the class AND all ancestors: 

    java.lang.reflect.Constructor<?>[] publicInheritedConstructors = someClass.getConstructors();
    java.lang.reflect.Method[] publicInheritedMethods = someClass.getMethods();
    java.lang.reflect.Field[] publicInheritedFields   = someClass.getFields();
  • 您可以通过java.lang.invoke.MethodHandles.Lookup将它们转换为MethodHandles:
        java.lang.invoke.MethodType mt; 
    java.lang.invoke.MethodHandle mh;
    java.lang.invoke.MethodHandles.Lookup lookup = MethodHandles.lookup();

    // process methods
    for (java.lang.reflect.Method method: declaredMethods) {
        mh = lookup.unreflect(method);

        // can call mh.invokeExact (requiring first parameter to be the class' 
        // object instance upon which the method will be invoked, followed by 
        // the methodparameter types, with an exact match parameter and return 
        // types) or
        // mh.invoke/invokeWithArguments (requiring first parameter to be the 
        // class' object instance upon which the method will be invoked, 
        // followed by the method parameter types, with compatible conversions 
        // performed on input/output types)
    }

    // process constructors
    for (java.lang.reflect.Constructor<?> constructor: declaredConstructors) {
        mh = lookup.unreflectConstructor(constructor);

        // can call mh.invokeExact or
        // mh.invoke/invokeWithArguments 
    }

    // process field setters
    for (java.lang.reflect.Field field: declaredFields) {
        mh = lookup.unreflectSetter(field);

        // can call mh.invokeExact or
        // mh.invoke/invokeWithArguments 
    }

    // process field getters
    for (java.lang.reflect.Field field: declaredFields) {
        mh = lookup.unreflectGetter(field);

        // can call mh.invokeExact or
        // mh.invoke/invokeWithArguments 
    }
  • 您可以通过java.lang.reflect确定方法/构造函数/字段的签名:
        // If generics involved in method signature:
    Type[] paramTypes = method.getGenericParameterTypes(); 
    Type returnType = method.getGenericReturnType(); 
    // Note: if Class is non-static inner class, first parameter of 
    // getGenericParameterTypes() is the enclosing class

    // If no generics involved in method signature:
    Class<?>[] paramTypes = declaredMethod.getParameterTypes(); 
    Class<?> returnType = declaredMethod.getReturnType(); 
    // Note: if Class is non-static inner class, first parameter of 
    // getParameterTypes() is the enclosing class

    // Same method calls for declaredConstructor
  • 您可以通过java.lang.reflect确定方法/构造函数/字段是否是静态的:
    int modifiers = method.getModifiers();  // same method for constructor/field
    

    boolean isStatic = java.lang.Modifier.isStatic(modifiers);

MethodHandle.invoke(),MethodHandle.invokeExact()和MethodHandle.invokeWithArguments()之间有什么区别?

  • 参见http://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html#invoke%28java.lang.Object...%29
  • 如果MethodHandle表示非静态方法,则提供给这些方法的第一个参数是Class声明该方法的实例。在该类的实例上调用该方法(对于静态方法,则在Class本身上)。如果Classs是非静态内部类,则第二个参数是封闭/声明类的实例。后续参数依次是方法签名参数。
  • invokeExact 不会对输入参数进行自动兼容的类型转换。它要求参数值(或参数表达式)是与方法签名完全匹配的类型,每个参数作为单独的参数提供,或者所有参数作为数组一起提供(签名:)Object invokeExact(Object... args)
  • invoke 要求参数值(或参数表达式)类型兼容以匹配方法签名-执行自动类型转换,每个参数作为单独的参数提供,或所有参数作为数组一起提供(签名:Object invoke(Object .. 。args))
  • invokeWithArguments 需要的参数值(或参数表达式)是类型兼容匹配方法签名-自动类型转换被执行,以列表内提供的每个参数(签名:Object invokeWithArguments(List<?> arguments)

对于使用MethodHandle API for Java devloper的教程,我将不胜感激。

不幸的是,那里没有太多东西。您可以尝试以下方法。希望我已经在上面给出了足够的信息:^)

[http://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html
](http://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html)  
[http://docs.oracle.com/javase/7/docs/api/java/lang/invoke
/MethodHandles.Lookup.html
](http://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandles.Lookup.html)  
[http://www.java7developer.com/blog/?p=191
](http://www.java7developer.com/blog/?p=191)  
[http://www.oraclejavamagazine-
digital.com/javamagazine/20130102?pg=52&search_term=methodhandle&doc_id=-1#pg50
](http://www.oraclejavamagazine-
digital.com/javamagazine/20130102?pg=52&search_term=methodhandle&doc_id=-1#pg50)  
[http: //www.amazon.com/Well-Grounded-Java-Developer-techniques-
programming/dp/1617290068](https://rads.stackoverflow.com/amzn/click/com/1617290068)
2020-10-18