标签: methodhandle

MethodHandle - 这是什么一回事?

我正在研究JDK 1.7的新功能,我无法得到它为MethodHandle设计的内容?我理解(直接)静态方法的调用(以及在这种情况下直接使用Core Reflection API).我也理解(直接)调用虚方法(非静态,非最终)(以及使用需要通过Class层次结构的Core Reflection API obj.getClass().getSuperclass()).非虚方法的调用可以视为前者的特殊情况.

是的,我知道存在重载问题.如果要调用方法,则必须提供确切的签名.您无法以简单的方式检查重载方法.

但是,MethodHandle是什么?Reflection API允许您"查看"对象内部,而无需任何预先假设(如实现接口).您可以出于某种目的检查对象.但是MethodHandle的设计是什么呢?我应该何时何地使用它?

更新:我现在正在阅读这篇http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html文章.根据它,主要目标是简化在JVM上运行的脚本语言的生命,而不是Java语言本身.

更新-2:我读完了上面的链接,从那里引用了一些引文:

JVM将成为构建动态语言的最佳VM,因为它已经是一个动态语言VM.而InvokeDynamic通过向一流的JVM公民推广动态语言,将证明这一点.

使用反射来调用方法效果很好......除了一些问题.必须从特定类型检索方法对象,并且不能以一般方式创建.<...>

...反射调用比直接调用慢很多.多年来,JVM已经非常擅长快速反映调用.现代JVM实际上在幕后生成了一堆代码,以避免处理大量开销的旧JVM.但简单的事实是,通过任意数量的层反射访问总是比直接调用慢,部分原因是完全通用的"调用"方法必须检查并重新检查接收器类型,参数类型,可见性和其他细节,但因为参数必须都是对象(所以原语是对象框),并且必须作为一个数组提供,以涵盖所有可能的arities(所以参数得到数组框).

对于执行少量反射调用的库,性能差异可能无关紧要,特别是如果这些调用主要是为了在内存中动态设置静态结构,可以进行正常调用.但是在动态语言中,每次调用必须使用这些机制,这是一个严重的性能损失.

http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html

因此,对于Java程序员来说,它基本上是无用的.我对吗?从这个角度来看,它只能被视为Core Reflection API的替代方式.

java jvm invokedynamic java-7 methodhandle

47
推荐指数
4
解决办法
1万
查看次数

如何提高Field.set的性能(使用MethodHandles进行perhap)?

我正在写一些调用的代码Field.setField.get数千次.显然,由于反射,这是非常缓慢的.

我想看看我是否可以MethodHandle在Java7中提高性能.到目前为止,这就是我所拥有的:

而不是field.set(pojo, value),我正在做:

private static final Map<Field, MethodHandle> setHandles = new HashMap<>();

MethodHandle mh = setHandles.get(field);
if (mh == null) {
    mh = lookup.unreflectSetter(field);
    setHandles.put(field, mh);
}
mh.invoke(pojo, value);
Run Code Online (Sandbox Code Playgroud)

但是,这似乎没有比使用反射的Field.set调用更好.我在这里做错了吗?

我读到使用invokeExact可能会更快,但当我尝试使用它时,我得到了一个java.lang.invoke.WrongMethodTypeException

有没有人成功地优化了对Field.set或Field.get的重复调用?

java reflection performance field methodhandle

38
推荐指数
4
解决办法
6262
查看次数

当MethodHandle更快时,为什么要使用反射来访问类成员?

随着Java 7的发布MethodHandle,它允许用户像使用其底层字节码一样调用方法.特别是,MethodHandles.Lookup该类提供工厂方法来创建访问类成员的方法句柄:

Lookup对象上的工厂方法对应于方法,构造函数和字段的所有主要用例.工厂方法创建的每个方法句柄都是特定字节码行为的功能等价物.

从功能上讲,这或多或少等同于使用反射来访问这些相同的类成员,但方法句柄比反射更快.

那么,有什么理由仍然使用反射功能一样Field#get(..)/ Method.invoke(..)或这些方法是引进了更快的方法手柄的有效过时了吗?

请注意,尽管在Java 7中引入了方法句柄,但我的问题主要与Java 8有关,在Java 8中,它们被优化为可以达到与直接字段/方法调用大致相等的性能,超过了反射的能力.

java reflection performance java-8 methodhandle

28
推荐指数
1
解决办法
4093
查看次数

使用MethodHandle查找最具体的重载方法

假设我在给定类型(类/接口)中有三个方法:

public void foo(Integer integer);
public void foo(Number number);
public void foo(Object object);
Run Code Online (Sandbox Code Playgroud)

使用MethodHandle或反射,我想找到一个对象的最具体的重载方法,该类型的类型仅在运行时已知.即我想在运行时执行JLS 15.12.

例如,假设我在上述类型的方法中包含以下三种方法:

Object object = getLong(); // runtime type is Long *just an example*

MethodHandles.lookup()
             .bind(this, "foo", methodType(Void.class, object.getClass()))
             .invoke(object);
Run Code Online (Sandbox Code Playgroud)

然后我在概念上会想要foo(Number number)被选中,但上面会抛出一个异常,因为API只会寻找一个foo(Long)方法,而不是别的.请注意,Long此处的用法仅作为示例.对象的类型可以是实践中的任何东西; String,MyBar,Integer,...等等

MethodHandle API中是否有一些东西能够在运行时自动执行与JLS 15.12之后的编译器相同的分辨率?

java reflection dynamic methodhandle

25
推荐指数
2
解决办法
869
查看次数

MethodHandle性能

我写了一个小的基准测试性能java.lang.invoke.MethodHandle,java.lang.reflect.Method和方法的直接调用.

我读到的MethodHandle.invoke()表现几乎与直接通话相同.但我的测试结果显示另一个:MethodHandle调用比反射慢大约三倍.我的问题是什么?可能这是一些JIT优化的结果?

public class Main {
    public static final int COUNT = 100000000;
    static TestInstance test = new TestInstance();

    static void testInvokeDynamic() throws NoSuchMethodException, IllegalAccessException {
        int [] ar = new int[COUNT];

        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(int.class);

        MethodHandle handle = lookup.findStatic(TestInstance.class, "publicStaticMethod", mt) ;

        try {
            long start = System.currentTimeMillis();

            for (int i=0; i<COUNT; i++) {
                ar[i] = (int)handle.invokeExact();
            }

            long stop = System.currentTimeMillis();

            System.out.println(ar);

            System.out.println("InvokeDynamic time: " + …
Run Code Online (Sandbox Code Playgroud)

java performance methodhandle

18
推荐指数
2
解决办法
5688
查看次数

关于Java-7中的签名多态方法

据我所知,随着Java 7中MethodHandle的引入,引入了编译器生成的方法重载.

MethodHandlejavadoc状态(我已经修剪了示例):

以下是一些用法示例:

Object x, y; String s; int i;
mh = ...
// (Ljava/lang/String;CC)Ljava/lang/String;
// (String, char, char) -> String
s = (String) mh.invokeExact("daddy",'d','n');

// (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
// (Object, Object, Object) -> Object
x = mh.invokeExact((Object)1, (Object)2, (Object)3);

// (Ljava/util/List;)I
// (List) -> int
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));

// (Ljava/io/PrintStream;Ljava/lang/String;)V
// (PrintStream, String) -> void
mh.invokeExact(System.out, "Hello, world.");
Run Code Online (Sandbox Code Playgroud)

上述每个调用都会生成一个invokevirtual指令,其名称为invoke,注释中指示的类型描述符.参数类型直接取自实际参数,而返回类型取自立即应用于调用的强制转换.这个演员可能是一个原始人.如果缺少,则如果在使用返回值的上下文中发生调用,则类型默认为Object.如果调用作为语句发生,则转换是不可能的,并且没有返回类型; 电话无效.

实际上,invokeExact和friends的行为就好像每个可能的参数组合和返回类型都有重载.

我听说MethodHandles正在为Java 8中的功能做准备,比如lambdas.(我知道它们对脚本语言已经很有用了.)

[/介绍]

那么,是否有更多这些编译器生成的重载隐藏在Java中?是否有提示将来会有更多这些提示(例如,使用扩展方法)?为什么首先需要它?仅速度?它如何帮助lambdas(我认为lambdas会编译成一个匿名的内部类)?

简而言之,理由是什么; 为什么它们(生成的重载)现在和将来都有用?

更新:我在这里称之为编译器生成的重载,Oracle人称之为签名多态.

java-7 java-8 methodhandle

11
推荐指数
1
解决办法
2079
查看次数

为什么我不能在这里使用.invokeExact(),即使MethodType没问题呢?

对于我的一个项目,我必须对构造函数进行动态调用.但由于这是Java 7,而不是"经典"反射API,我使用java.lang.invoke.

码:

@ParametersAreNonnullByDefault
public class PathMatcherProvider
{
    private static final MethodHandles.Lookup LOOKUP
        = MethodHandles.publicLookup();
    private static final MethodType CONSTRUCTOR_TYPE
        = MethodType.methodType(void.class, String.class);

    private final Map<String, Class<? extends PathMatcher>> classMap
        = new HashMap<>();
    private final Map<Class<? extends PathMatcher>, MethodHandle> handleMap
        = new HashMap<>();

    public PathMatcherProvider()
    {
        registerPathMatcher("glob", GlobPathMatcher.class);
        registerPathMatcher("regex", RegexPathMatcher.class);
    }

    public final PathMatcher getPathMatcher(final String name, final String arg)
    {
        Objects.requireNonNull(name);
        Objects.requireNonNull(arg);

        final Class<? extends PathMatcher> c = classMap.get(name);
        if (c == null)
            throw new UnsupportedOperationException();

        try {
            return …
Run Code Online (Sandbox Code Playgroud)

java java-7 methodhandle

11
推荐指数
2
解决办法
1655
查看次数

是否可以将方法引用转换为MethodHandle?

是否可以将方法引用(例如SomeClass::someMethod)转换为MethodHandle实例?我想要编译时检查的好处(确保存在类和方法)以及使用MethodHandleAPI 内省方法的能力.

用例:当且仅当请求未被特定方法触发时(以避免无限递归),我才需要执行代码.我想要一个编译时检查以确保类/方法存在但运行时检查以将调用者与方法进行比较.

所以回顾一下:是否可以将方法引用转换为MethodHandle

java java-8 methodhandle method-reference

10
推荐指数
1
解决办法
1033
查看次数

MethodHandles还是LambdaMetafactory?

在我的工作中,我们有一个用于指定数学公式的DSL,我们后来应用于很多点(数百万).

截至今天,我们构建公式的AST,并访问每个节点以产生我们称之为"评估者"的东西.然后,我们向该求值程序传递公式的参数,并为每个点进行计算.

例如,我们有这个公式: x * (3 + y)

           ??????
     ???????mult???????
     ?     ??????     ?
     ?                ?
  ???v???          ???v???
  ?  x  ?      ????? add ????
  ???????      ?   ???????  ?
               ?            ?
            ???v???      ???v???
            ?  3  ?      ?  y  ?
            ???????      ???????
Run Code Online (Sandbox Code Playgroud)

我们的评估员将为每个步骤发出"评估"对象.

这种方法易于编程,但效率不高.

所以我开始研究方法句柄来构建一个"组合"的方法句柄,以加快最近的速度.

这样的事情:我有我的"算术"课:

public class Arithmetics {

  public static double add(double a, double b){
      return a+b;
  }

  public static double mult(double a, double b){
      return a*b;
  }

}
Run Code Online (Sandbox Code Playgroud)

在构建我的AST时,我使用MethodHandles.lookup()来直接获取它们的句柄并组合它们.沿着这些方向的东西,但在一棵树上:

Method add = ArithmeticOperator.class.getDeclaredMethod("add", double.class, double.class);
Method mult = ArithmeticOperator.class.getDeclaredMethod("mult", double.class, …
Run Code Online (Sandbox Code Playgroud)

java lambda invokedynamic java-8 methodhandle

8
推荐指数
1
解决办法
728
查看次数

java.lang.NoSuchMethodError:VarHandle.compareAndSet(VariableHandlesExample,State,State)void

VarHandle显示以下错误 -

Exception in thread "main" java.lang.NoSuchMethodError: VarHandle.compareAndSet(VarHandleExample,int,int)void
    at java.base/java.lang.invoke.MethodHandleNatives.newNoSuchMethodErrorOnVarHandle(MethodHandleNatives.java:492)
    at java.base/java.lang.invoke.MethodHandleNatives.varHandleOperationLinkerMethod(MethodHandleNatives.java:445)
    at java.base/java.lang.invoke.MethodHandleNatives.linkMethodImpl(MethodHandleNatives.java:378)
    at java.base/java.lang.invoke.MethodHandleNatives.linkMethod(MethodHandleNatives.java:366)
    at j9.VarHandleExample.update(VarHandleExample.java:23)
    at j9.VarHandleExample.main(VarHandleExample.java:14)
Run Code Online (Sandbox Code Playgroud)

我的计划是:

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;

public class VarHandleExample {
    public int publicTestVariable = 10;
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        VarHandleExample e= new VarHandleExample();
        e.update();
    }
    public void update() throws NoSuchFieldException, IllegalAccessException {
        VarHandle publicIntHandle = MethodHandles.lookup()
              .in(VariableHandlesTest.class)
              .findVarHandle(VarHandleExample.class, "publicTestVariable", int.class);
        publicIntHandle.compareAndSet(this, 10, 100); // CAS
    }
}
Run Code Online (Sandbox Code Playgroud)

java methodhandle java-9

8
推荐指数
1
解决办法
183
查看次数