据我所知,随着Java 7中MethodHandle的引入,引入了编译器生成的方法重载。
javadoc for MethodHandle个州(我已经修改过这些例子):
以下是一些使用示例:
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指令 名称调用和类型描述符 评论。参数类型直接取自实际 参数,而返回类型是立即从演员表中获取的 适用于通话。这个演员可能是一个原始人。如果是 缺少,如果在上下文中发生调用,则类型默认为Object 它使用返回值。如果调用作为语句,强制转换发生 是不可能的,没有回归类型;电话无效。
实际上,invokeExact和friends的行为就好像每个可能的参数组合和返回类型都有重载。
我听说MethodHandles正在为像lambdas这样的Java 8中的功能做准备。 (我知道它们对脚本语言已经很有用了。)
[/介绍]
那么,是否有更多这些编译器生成的重载隐藏在Java中?是否有提示将来会有更多这些提示(例如,使用扩展方法)?为什么首先需要它?仅速度?它如何帮助lambdas(我认为lambdas会编译成匿名的内部类)?
简而言之,理由是什么;为什么它们(生成的重载)现在和未来都有用?
更新:我称之为编译器生成的重载,Oracle人员称签名多态。
答案 0 :(得分:12)
我刚刚在MethodHandles and invokedynamic
上遇到了Hotspot internals wiki它提出了一些有趣的观点来回答这些问题(以及其他一些问题)。
MethodHandle.invokeExact
和朋友是唯一的,是唯一的签名多态方法。invokevirtual
字节码被秘密转换为 invokehandle
指令。
invokehandle
就像invokedynamic
;一些内部结构是不同的,并且每个invokedynamic
指令必须指向它自己的常量池缓存条目(CPCE),invokehandle
可以共享CPCE。invokedynamic
使用HotSpot VM上的非公开 MethodHandle.invokeBasic
MethodHandle.invokeBasic
就像invokeExact但更松散;例如,它不会检查呼叫站点的类型与被叫方的类型。invokedynamic
)可以 JIT编译 此外, lambda表达式将为implemented via invokedynamic
。 (来自Edwin Dalorzo的回答。)这意味着lambda表达式
MethodHandle.invokeBasic
(见上文)和答案 1 :(得分:4)
这两个链接可能无法解答您的所有问题,但它们可能是一个很好的起点:
这是来自目前在JDK 8:Lambda项目中工作的专家组的参考资料。幸运的是,你可以在那里找到一些解释,最重要的是你对lambda表达式作为内部类的错误概念。