<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=JVM_InvokeDynamic</id>
	<title>JVM InvokeDynamic - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=JVM_InvokeDynamic"/>
	<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;action=history"/>
	<updated>2026-06-02T19:17:32Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.42.3</generator>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=3830&amp;oldid=prev</id>
		<title>2023年12月19日 (二) 09:07 Riguz</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=3830&amp;oldid=prev"/>
		<updated>2023-12-19T09:07:08Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2023年12月19日 (二) 09:07的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l287&quot;&gt;第287行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第287行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [https://www.jianshu.com/p/d74e92f93752 理解 invokedynamic]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [https://www.jianshu.com/p/d74e92f93752 理解 invokedynamic]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Category:&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Pinned&lt;/del&gt;]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Category:&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;JVM&lt;/ins&gt;]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key wiki_db:diff:1.41:old-3828:rev-3830:php=table --&gt;
&lt;/table&gt;</summary>
		<author><name>Riguz</name></author>
	</entry>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=3828&amp;oldid=prev</id>
		<title>Riguz：​Riguz移动页面Blog:浅析Java中的InvokeDynamic至JVM InvokeDynamic，不留重定向</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=3828&amp;oldid=prev"/>
		<updated>2023-12-19T09:06:25Z</updated>

		<summary type="html">&lt;p&gt;Riguz移动页面&lt;a href=&quot;/index.php?title=Blog:%E6%B5%85%E6%9E%90Java%E4%B8%AD%E7%9A%84InvokeDynamic&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Blog:浅析Java中的InvokeDynamic（页面不存在）&quot;&gt;Blog:浅析Java中的InvokeDynamic&lt;/a&gt;至&lt;a href=&quot;/JVM_InvokeDynamic&quot; title=&quot;JVM InvokeDynamic&quot;&gt;JVM InvokeDynamic&lt;/a&gt;，不留重定向&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2023年12月19日 (二) 09:06的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;zh-Hans-CN&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;（没有差异）&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Riguz</name></author>
	</entry>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=2579&amp;oldid=prev</id>
		<title>2021年7月5日 (一) 04:43 Riguz</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=2579&amp;oldid=prev"/>
		<updated>2021-07-05T04:43:00Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2021年7月5日 (一) 04:43的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l287&quot;&gt;第287行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第287行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [https://www.jianshu.com/p/d74e92f93752 理解 invokedynamic]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [https://www.jianshu.com/p/d74e92f93752 理解 invokedynamic]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;邮件阅读体验不佳，如需更好体验可以移步 &lt;/del&gt;[&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;https&lt;/del&gt;:&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;//riguz.com/it/java/java_invokedynamic/ 在线版本&lt;/del&gt;]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;[Category&lt;/ins&gt;:&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Pinned]&lt;/ins&gt;]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Riguz</name></author>
	</entry>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=2578&amp;oldid=prev</id>
		<title>2021年7月5日 (一) 04:42 Riguz</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=2578&amp;oldid=prev"/>
		<updated>2021-07-05T04:42:31Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2021年7月5日 (一) 04:42的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l12&quot;&gt;第12行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第12行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;大部分我们顾名思义，都可以知道是大概是干啥的，比如字符串啊，数字啊，方法名称之类的；但是可以注意到最后面一个是称之为`CONSTANT_InvokeDynamic`的常量，这个就有点陌生了。那么，这是一个什么样的常量？什么情况下会出现这个呢？&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;大部分我们顾名思义，都可以知道是大概是干啥的，比如字符串啊，数字啊，方法名称之类的；但是可以注意到最后面一个是称之为`CONSTANT_InvokeDynamic`的常量，这个就有点陌生了。那么，这是一个什么样的常量？什么情况下会出现这个呢？&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;[[Image:Strong-Duck-Typing.jpeg]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;= `invokedynamic`指令=&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;= `invokedynamic`指令=&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Riguz</name></author>
	</entry>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=2577&amp;oldid=prev</id>
		<title>imported&gt;Riguz：​Java语言在被编译成class文件后，在class文件中，有专门的一个[“常量池”(Constant Pool)](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4)区域来存储一些运行所需要的常量，包括一些写死的变量（比如定义一个字符串`String str = &quot;Hello world&quot;`以及一些符号，例如类和方法的的名称等）。在JVM(se7)规范中，有以下这些类型的常量：

```bash
CONSTANT_Class 	                         CONSTANT_Long 	          
CONSTANT_Fieldref 	                     CONSTANT_Double 	      
CONSTANT_Methodref 	                     CONSTANT_NameAndType 	  
CONSTANT_InterfaceMethodref              CONSTANT_Utf8…</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=JVM_InvokeDynamic&amp;diff=2577&amp;oldid=prev"/>
		<updated>2019-12-24T00:00:00Z</updated>

		<summary type="html">&lt;p&gt;Java语言在被编译成class文件后，在class文件中，有专门的一个[“常量池”(Constant Pool)](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4)区域来存储一些运行所需要的常量，包括一些写死的变量（比如定义一个字符串`String str = &amp;quot;Hello world&amp;quot;`以及一些符号，例如类和方法的的名称等）。在JVM(se7)规范中，有以下这些类型的常量：  ```bash CONSTANT_Class 	                         CONSTANT_Long 	           CONSTANT_Fieldref 	                     CONSTANT_Double 	       CONSTANT_Methodref 	                     CONSTANT_NameAndType 	   CONSTANT_InterfaceMethodref              CONSTANT_Utf8…&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Java语言在被编译成class文件后，在class文件中，有专门的一个[https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4 “常量池”(Constant Pool)]区域来存储一些运行所需要的常量，包括一些写死的变量（比如定义一个字符串`String str = &amp;quot;Hello world&amp;quot;`以及一些符号，例如类和方法的的名称等）。在JVM(se7)规范中，有以下这些类型的常量：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
CONSTANT_Class 	                         CONSTANT_Long 	          &lt;br /&gt;
CONSTANT_Fieldref 	                     CONSTANT_Double 	      &lt;br /&gt;
CONSTANT_Methodref 	                     CONSTANT_NameAndType 	  &lt;br /&gt;
CONSTANT_InterfaceMethodref              CONSTANT_Utf8 	          &lt;br /&gt;
CONSTANT_String 	                     CONSTANT_MethodHandle 	  &lt;br /&gt;
CONSTANT_Integer 	                     CONSTANT_MethodType 	  &lt;br /&gt;
CONSTANT_Float 	                         CONSTANT_InvokeDynamic 	  &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
大部分我们顾名思义，都可以知道是大概是干啥的，比如字符串啊，数字啊，方法名称之类的；但是可以注意到最后面一个是称之为`CONSTANT_InvokeDynamic`的常量，这个就有点陌生了。那么，这是一个什么样的常量？什么情况下会出现这个呢？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= `invokedynamic`指令=&lt;br /&gt;
在JVM规范中有说，`CONSTANT_InvokeDynamic`常量是用来给`invokedynamic`指令指定一系列的参数的，那么有必要先了解一下`invokedynamic`这个指令了。这是Java 7引入的一个新指令，也是自Java 1.0以来第一次引入新的指令。&lt;br /&gt;
&lt;br /&gt;
== Java7之前的`invoke-`指令==&lt;br /&gt;
实际上，在此之前，已经有一些列的`invoke`开头的指令了：&lt;br /&gt;
&lt;br /&gt;
* `invokevirtual`：用来调用类的实例方法，也就是最普遍的方式&lt;br /&gt;
* `invokestatic`：用来调用静态方法&lt;br /&gt;
* `invokeinterface`：用来调用通过接口调用的方法&lt;br /&gt;
* `invokespecial`：用来调用一些编译时就能够确定的，包括初始化(`&amp;lt;init&amp;gt;`)、类的私有方法，以及父类的方法(`super.someMethod()`)&lt;br /&gt;
&lt;br /&gt;
拿一个简单的Java程序来看看是怎么回事：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
// Foo.java&lt;br /&gt;
public class Foo {&lt;br /&gt;
    public static void main(String[] args) {&lt;br /&gt;
        long now = System.currentTimeMillis();            //静态方法调用&lt;br /&gt;
&lt;br /&gt;
        ArrayList&amp;lt;String&amp;gt; arrayList =  new ArrayList&amp;lt;&amp;gt;(); //构造函数将被调用&lt;br /&gt;
        List&amp;lt;String&amp;gt; list = arrayList;&lt;br /&gt;
&lt;br /&gt;
        arrayList.add(&amp;quot;hello&amp;quot;);                           //调用类实例方法&lt;br /&gt;
        list.add(&amp;quot;world&amp;quot;);                                //通过接口调用&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
通过`javac Foo.java &amp;amp;&amp;amp; javap -v Foo`可以查看编译后生成的class文件，里面可以找到`invoke`相关的指令调用：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public static void main(java.lang.String[]);&lt;br /&gt;
    descriptor: ([Ljava/lang/String;)V&lt;br /&gt;
    flags: ACC_PUBLIC, ACC_STATIC&lt;br /&gt;
    Code:&lt;br /&gt;
      stack=2, locals=5, args_size=1&lt;br /&gt;
         0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J&lt;br /&gt;
         3: lstore_1&lt;br /&gt;
         4: new           #3                  // class java/util/ArrayList&lt;br /&gt;
         7: dup&lt;br /&gt;
         8: invokespecial #4                  // Method java/util/ArrayList.&amp;quot;&amp;lt;init&amp;gt;&amp;quot;:()V&lt;br /&gt;
        11: astore_3&lt;br /&gt;
        12: aload_3&lt;br /&gt;
        13: astore        4&lt;br /&gt;
        15: aload_3&lt;br /&gt;
        16: ldc           #5                  // String hello&lt;br /&gt;
        18: invokevirtual #6                  // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z&lt;br /&gt;
        21: pop&lt;br /&gt;
        22: aload         4&lt;br /&gt;
        24: ldc           #7                  // String world&lt;br /&gt;
        26: invokeinterface #8,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z&lt;br /&gt;
        31: pop&lt;br /&gt;
        32: return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
这样就比较好理解了，就跟我们平常调用函数一样，&lt;br /&gt;
&lt;br /&gt;
* `System.currentTimeMillis()`静态函数的调用生成了`invokestatic`指令，这个指令的参数是静态方法（包含类名和方法名）&lt;br /&gt;
* `ArrayList`的构造方法调用生成了`invokespecial`指令，这里在`new`指令之后接着使用`invokespecial`指令来进行初始化操作&lt;br /&gt;
* 通过`ArrayList`的实例方法`add`调用生成了`invokevirtual`指令&lt;br /&gt;
* 而通过`List`接口的`add`方法调用生成了`invokeinterface`指令&lt;br /&gt;
&lt;br /&gt;
尽管已经有了以上的四种指令，这些指令都有一个特点，那就是不管是什么方法，是静态还是实例方法，是子类还是父类的方法，在编译的时候已经能够确定出到底会调用到哪个方法了。有没有一种可能，就是我在编译的时候不能确定，而是在运行的时候才能确定呢？&lt;br /&gt;
&lt;br /&gt;
== 鸭子类型（***Duck Typing***）==&lt;br /&gt;
&lt;br /&gt;
这就是所谓的[https://zh.wikipedia.org/wiki/%E9%B8%AD%E5%AD%90%E7%B1%BB%E5%9E%8B 鸭子类型]了，可能叫***Duck typing***其实更好理解一点，这个名称来源自[https://zh.wikipedia.org/wiki/%E9%B8%AD%E5%AD%90%E6%B5%8B%E8%AF%95 鸭子测试]:&lt;br /&gt;
&lt;br /&gt;
&amp;gt; “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子，那么这只鸟就可以被称为鸭子。”&lt;br /&gt;
&lt;br /&gt;
[[File:https://devopedia.org/images/article/24/2998.1514520209.jpg|600px|A humorous and apt representation of duck typing. Source: Mastracci, 2014.]]&lt;br /&gt;
&lt;br /&gt;
我们知道，Java是一个强类型的语言，有很多的类型检查，比如你要调用某个接口，而被调用的对象没有实现这个接口那么是无法完成的。而Duck Typing正如上面这个图片形象的表示，我并不关心对象本身是个什么东西，而关心这个对象是否支持我所需要的所有属性或者方法。维基百科上的这个伪代码可以更直接的解释：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function calculate(a, b, c) =&amp;gt; return (a+b)*c&lt;br /&gt;
&lt;br /&gt;
example1 = calculate (1, 2, 3)&lt;br /&gt;
example2 = calculate ([1, 2, 3], [4, 5, 6], 2)&lt;br /&gt;
example3 = calculate (&amp;#039;apples &amp;#039;, &amp;#039;and oranges, &amp;#039;, 3)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
这些对象没有使用继承或者其他的方式相互发生联系，但只要它们支持`+`和`*`这两个方法，调用就可以成功。`invokedyanmic`指令从某种程度上来说，就是为了支持*Duck typing*。&lt;br /&gt;
&lt;br /&gt;
看到这里可能细心的读者会注意到，咦，这东西看着好像`lambda`?&lt;br /&gt;
&lt;br /&gt;
没错，事实上`lambda`的确是跟`invokedynamic`有关的，但有意思的是`lambda`是直到Java 8才推出（[https://www.jcp.org/en/jsr/detail?id=335 JSR 335: Lambda Expressions for the JavaTM Programming Language])。在此之前，是无法通过`javac`编译器生成包含这个指令的class的。`invokedynamic`指令是在[https://jcp.org/en/jsr/detail?id=292 JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform]中被引入的，可以注意到，原本是为了支持基于JVM的动态语言，并不是说要在Java中来做Duck typing，这样就比较合理了。&lt;br /&gt;
&lt;br /&gt;
当然借助于一些字节码操作框架（例如[http://www.csg.is.titech.ac.jp/~chiba/javassist/ Javassit]、[http://asm.ow2.org/ ASM]等，是可以手动创造出含有`invokedynamic`的class的，不过会有些麻烦。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== lambda与invokedynamic==&lt;br /&gt;
如果我们用支持`lambda`的Java 8是可以很容易的创建出一个包含`invokedynamic`常量和指令的class的，比如下面这个例子：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
import java.util.function.*;&lt;br /&gt;
&lt;br /&gt;
public class Hello {&lt;br /&gt;
&lt;br /&gt;
    public static void main(String[] args) {&lt;br /&gt;
        Supplier&amp;lt;String&amp;gt; welcome = () -&amp;gt; &amp;quot;Hello world!&amp;quot;;&lt;br /&gt;
        System.out.println(welcome.get());&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
当查看编译后的class文件会发现有下面的部分：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Constant pool:&lt;br /&gt;
   #1 = Methodref          #9.#20         // java/lang/Object.&amp;quot;&amp;lt;init&amp;gt;&amp;quot;:()V&lt;br /&gt;
   #2 = InvokeDynamic      #0:#26         // #0:get:()Ljava/util/function/Supplier;&lt;br /&gt;
&lt;br /&gt;
public static void main(java.lang.String[]);&lt;br /&gt;
    descriptor: ([Ljava/lang/String;)V&lt;br /&gt;
    flags: ACC_PUBLIC, ACC_STATIC&lt;br /&gt;
    Code:&lt;br /&gt;
      stack=2, locals=2, args_size=1&lt;br /&gt;
         0: invokedynamic #2,  0              // InvokeDynamic #0:get:()Ljava/util/function/Supplier;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
一个就是在常量池中可以看到一个InvokeDynamic类型的常量，指向了`Supplier.get()`方法；另一个就是在`main`方法中对lambda的调用，被编译成`invokedynamic`指令。&lt;br /&gt;
&lt;br /&gt;
= invokedynamic的机制=&lt;br /&gt;
来研究一下`invokedyanmic`到底是怎么工作的吧。要了解它怎么工作的，我们先要知道编译生成的class文件中有些什么。刚我们看到，class文件中有两个部分与之相关，一个是常量池中的InvokeDyanmic信息，另一个是方法字节码中的`invokedynamic`指令调用。实际上JVM在引入这个新指令的同时，也在常量池(Constant Pool)和属性表(Attributes)中加入了与之相关的内容，也就是`CONSTANT_InvokeDynamic_info`和`BootstrapMethods_attribute`。得益于class文件的扩展性，这些改动实际上并没有改变class文件本身的结构，仅仅只是加了更多合法的选项在里边。&lt;br /&gt;
&lt;br /&gt;
== 引导函数(Bootstrap method)表==&lt;br /&gt;
在class的`Attributes`（属性表）中新加入的一个`BootstrapMethods_attribute`属性，这个属性里面会存储一些函数的相关信息，而且是和`CONSTANT_InvokeDynamic`常量一一对应的。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
BootstrapMethods_attribute {&lt;br /&gt;
    u2 attribute_name_index;&lt;br /&gt;
    u4 attribute_length;&lt;br /&gt;
    u2 num_bootstrap_methods;&lt;br /&gt;
    {   u2 bootstrap_method_ref;&lt;br /&gt;
        u2 num_bootstrap_arguments;&lt;br /&gt;
        u2 bootstrap_arguments[num_bootstrap_arguments];&lt;br /&gt;
    } bootstrap_methods[num_bootstrap_methods];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
每一个引导函数都包含几个重要的属性： &lt;br /&gt;
&lt;br /&gt;
* bootstrap_method_ref: 指向一个`CONSTANT_MethodHandle_info`引用，表明实际调用的方法信息&lt;br /&gt;
* bootstrap_arguments: 对应这个函数的参数&lt;br /&gt;
&lt;br /&gt;
这个引导函数通常是这个样子：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
static CallSite bootstrapMethod(MethodHandles.Lookup caller, String name, MethodType type);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
这个函数返回一个调用点([https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/CallSite.html CallSite])对象，这个对象包含了方法调用所需要的一切信息，用来给`invokedynamic`指令使用。&lt;br /&gt;
&lt;br /&gt;
在Java8的`java.lang.invoke.LambdaMetafactory`类中，对应也增加定义了两个用来支持调用lambda的引导函数：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
static CallSite altMetafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, &lt;br /&gt;
                               Object... args);&lt;br /&gt;
static CallSite metafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, &lt;br /&gt;
                            MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
而在上面的例子中，这个引导函数是这样的：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BootstrapMethods:&lt;br /&gt;
  0: #22 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;&lt;br /&gt;
    Method arguments:&lt;br /&gt;
      #23 ()Ljava/lang/Object;&lt;br /&gt;
      #24 invokestatic Hello.lambda$main$0:()Ljava/lang/String;&lt;br /&gt;
      #25 ()Ljava/lang/String;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== InvokeDynamic常量==&lt;br /&gt;
&lt;br /&gt;
InvokeDynamic常量的定义如下：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
CONSTANT_InvokeDynamic_info {&lt;br /&gt;
    u1 tag;&lt;br /&gt;
    u2 bootstrap_method_attr_index;&lt;br /&gt;
    u2 name_and_type_index;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
其中`bootstrap_method_attr_index`指向一个引导函数(Bootstrap method)的序号，`name_and_type_index`则表明方法的名称和描述。在上面的例子中，仅有一个引导函数，这个`bootstrap_method_attr_index`自然就是对应到这个引导函数了。而在`invokedynamic`指令调用的地方，是这样的：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
invokedynamic #2,  0              // InvokeDynamic #0:get:()Ljava/util/function/Supplier;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
其中这个`#2`即常量池中的`InvokeDynamic`常量。&lt;br /&gt;
&lt;br /&gt;
== `invokedynamic`指令==&lt;br /&gt;
&lt;br /&gt;
根据[https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokedynamic JVM的规范]中的描述可以看到`invokedynamic`指令的格式如下：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
invokedynamic indexbyte1 indexbyte2 0 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
其中前两个操作数可以通过`(indexbyte1 &amp;lt;&amp;lt; 8) | indexbyte2`的方式合成一个常量池中的索引值，也就是上面的`#2`，而另外两个操作数是固定的0。&lt;br /&gt;
&lt;br /&gt;
= Labmda的JVM实现=&lt;br /&gt;
&lt;br /&gt;
刚才已经看到，Java中对lambda&amp;#039;的调用实际上通过`LambdaMetafactory.metafactory`来完成的，通过了解这个类的实现，可以一看lambda的究竟。&lt;br /&gt;
&lt;br /&gt;
[[File:debug_metafactory.png|600px|Debug metafactory]]&lt;br /&gt;
&lt;br /&gt;
在这个类里面创建了一个匿名类，并通过`UNSAFE.ensureClassInitialized(innerClass)`直接加载到JVM中，没有出现在class文件中，不过通过jvm参数可以输出出来：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
java -Djdk.internal.lambda.dumpProxyClasses=/Users/hfli/Downloads/tmp Hello&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
这样会生成一个`Hello$$Lambda$1.class`的文件，反编译这个类可以看到如下的信息：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
final class Hello$$Lambda$1 implements Supplier {&lt;br /&gt;
    private Hello$$Lambda$1() {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Hidden&lt;br /&gt;
    public Object get() {&lt;br /&gt;
        return Hello.lambda$main$0();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
这里实际是包装了一下`Supplier`接口，而具体调用的`Hello.lambda$main$0()`方法，可以在`Hello.class`文件中看到（需要使用`javap -p`选项输出私有方法):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private static java.lang.String lambda$main$0();&lt;br /&gt;
    descriptor: ()Ljava/lang/String;&lt;br /&gt;
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC&lt;br /&gt;
    Code:&lt;br /&gt;
      stack=1, locals=0, args_size=0&lt;br /&gt;
         0: ldc           #7                  // String Hello world!&lt;br /&gt;
         2: areturn&lt;br /&gt;
      LineNumberTable:&lt;br /&gt;
        line 6: 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
所以大致是这个样子的过程：&lt;br /&gt;
&lt;br /&gt;
* 调用lambda时，首先通过找到对应的引导方法（也就是`metafactory()`)，开始执行&lt;br /&gt;
* JVM生成一个匿名类`Hello$$Lambda$1`，这个类中包含了lambda的实际实现&lt;br /&gt;
* 创建一个CallSite，绑定到一个MethodHandle指向这个匿名类的实现`Hello$$Lambda$1.get()`。这里引导方法就调用完成了&lt;br /&gt;
* 这个MethodHandle指向的方法被执行，调用到`Hello.lambda$main$0()`关联的字节码，得到最终的结果&lt;br /&gt;
&lt;br /&gt;
值得注意的是，引导方法只需要执行一次，如果一个lambda执行了多次，那么只有第一次会去调用引导方法生成CallSite，以后都可以直接拿来使用了。&lt;br /&gt;
&lt;br /&gt;
= 结语=&lt;br /&gt;
&lt;br /&gt;
通过上面的描述，相信大家对`invokedynamic`有了一个粗略的了解，但要真正深入去了解的话，还是有很多东西需要去了解和研究的。虽然`invokedynamic`指令很强大，给了JVM的开发者很大的自由度，但实际上对于Java程序员来说，并没有太多可以操控的东西。如同上面提到的Duck Typing，在C#中可以这样：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c#&amp;quot;&amp;gt;&lt;br /&gt;
Object obj = ...; // no static type available &lt;br /&gt;
dynamic duck = obj;&lt;br /&gt;
duck.quack();     // or any method. no compiler checking.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
可能我们永远也没法使用Java来完成同样的任务，也许有一部分人会比较失望，但本身这是一把双刃剑，我还是倾向[http://www.yinwang.org/blog-cn/2016/01/18/java 给Java说句公道话]。而借助于JVM平台，我们实际上有了越来越多的选择，Scala, Kotlin，Groovy等等。可以说从某个方面来讲，正是Java决策者对于每一个决策的慎重，才造就了今天Java程序员不愁饭吃的局面。&lt;br /&gt;
&lt;br /&gt;
&amp;gt; &amp;quot;When you have 9 million programmers using your language and out of which 1 million programmers know where you live you have to decide things differently.&amp;quot;&lt;br /&gt;
&amp;gt; ——[https://www.youtube.com/watch?v=1OpAgZvYXLQ&amp;amp;t=1993s Venkat Subramaniam]&lt;br /&gt;
&lt;br /&gt;
参考文章：&lt;br /&gt;
&lt;br /&gt;
* [https://www.infoq.com/articles/Invokedynamic-Javas-secret-weapon/ Invokedynamic - Java’s Secret Weapon]&lt;br /&gt;
* [https://stackoverflow.com/questions/6638735/whats-invokedynamic-and-how-do-i-use-it What&amp;#039;s invokedynamic and how do I use it?]&lt;br /&gt;
* [https://zh.wikipedia.org/wiki/%E9%B8%AD%E5%AD%90%E7%B1%BB%E5%9E%8B Duck Typing - Wiki]&lt;br /&gt;
* [https://devopedia.org/duck-typing Duck Typing]&lt;br /&gt;
* [http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html A First Taste of InvokeDynamic]&lt;br /&gt;
* [https://www.javacodegeeks.com/2012/02/java-7-complete-invokedynamic-example.html Java 7: A complete invokedynamic example]&lt;br /&gt;
* [https://my.oschina.net/lt0314/blog/3146028 你不知道Lambda的秘密和陷阱]&lt;br /&gt;
* [http://wiki.jvmlangsummit.com/images/9/93/2011_Forax.pdf JSR 292 Cookbook]&lt;br /&gt;
* [https://www.jianshu.com/p/d74e92f93752 理解 invokedynamic]&lt;br /&gt;
&lt;br /&gt;
邮件阅读体验不佳，如需更好体验可以移步 [https://riguz.com/it/java/java_invokedynamic/ 在线版本]&lt;/div&gt;</summary>
		<author><name>imported&gt;Riguz</name></author>
	</entry>
</feed>