12

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

MethodHandle的javadoc状态(我已经修剪了示例):

以下是一些使用示例:

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.");

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

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

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

[/介绍]

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

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

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

4

2 回答 2

15

我刚刚在MethodHandles 和 invokedynamic上看到了一个 Hotspot 内部 wiki

它提出了一些有趣的观点来回答这些问题(以及更多)。

  • 问题中所谓的编译器生成的重载,java 家伙称签名多态。
  • MethodHandle.invokeExact和朋友是独一无二的,是唯一的签名多态方法。
  • 在 HotSpot VM 上,invokevirtualMethodHandle.invoke* 的字节码被秘密转换为invokehandle指令。
    • invokehandle就像invokedynamic; 一些内部结构不同,每条invokedynamic指令必须指向它自己的常量池缓存条目(CPCE),invokehandles 可以共享 CPCE。
  • invokedynamicMethodHandle.invokeBasic在 HotSpot VM 上 使用非公共
    • MethodHandle.invokeBasic类似于 invokeExact 但更松散;一方面,它不会检查调用站点的类型与被调用者的类型。
  • 热方法句柄(包括invokedynamic)可以进行JIT 编译

此外,lambda 表达式通过invokedynamic. (从 Edwin Dalorzo 的回答中得到。)这意味着 lambda 表达式

  • 将间接MethodHandle.invokeBasic在 HotSpot VM 上使用(见上文),并且
  • 有资格进行 JIT 编译
于 2012-12-22T06:17:43.947 回答
4

这两个链接可能无法回答您的所有问题,但它们可能是一个很好的起点:

这是来自目前在 JDK 8:Project Lambda 中工作的专家组的参考资料。幸运的是,您可以在那里找到一些解释,尤其是关于您对 lambda 表达式作为内部类的误解。

于 2012-12-21T12:26:22.090 回答