问:第14行是什么意思?
使用javap -v -c来反汇编以下代码:
public class test {
static int i = 2;
public static void main(String[] args) {
test x = new test();
System.out.println("text + String: " + i);
}
}在主要功能中,我们得到以下内容:
14: invokedynamic #20, 0 // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
19: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
...
BootstrapMethods:
0: #38 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
Method arguments:
#44 text + String: \u0001因此,例如,第19行意味着运行时常量池中#24项中的invokevirtual。被调用的方法是来自类println()的java/io/PrintStream,它的输入来自类Ljava/lang/String,其返回值是无效的。
至于第14行,#0保存对BootstrapMethod的引用,并返回一个类为CallSite正确的对象?然后:
#0:makeConcatWithConstants:(I)Ljava/lang/String;的评论是什么意思?另外,在哪里可以找到关于Javap反汇编代码的语法的更多信息?或者什么是正确的关键字?甲骨文关于the JVM instruction set的文件似乎没有清楚地描述评论的意义。
发布于 2020-04-28 21:05:04
简短的版本: Java使用invokedynamic连接自Java 9以来的字符串。
让我们把这一点分解一下:
Invokedynamic有两个步骤:
CallSite只是MethodHandle的持有者。根据所使用的CallSite子类,该站点稍后可能会重新链接。
如果我们看一下这条指令,我们会在最后看到以下内容:
#0:makeConcatWithConstants:(I)Ljava/lang/String;第一部分(#0)的意思是:引导方法#0。
第二部分是名称--它传递给引导方法,可以在那里使用,也可以不使用。
第三部分是结果目标的方法类型。在本例中:获取int并返回java.lang.String的方法。
如果我们现在看一下引导方法#0,我们会看到一个方法引用,这里是StringConcatFactory.makeConcatWithConstants(...)。我们还看到了另一个参数:字符串"text + String: \u0001"。
引导方法现在的任务是返回一个MethodHandle (在CallSite中),在这种情况下,这个字符串连接。但是它是如何进行字符串连接的(StringBuilder,String.format,字节码旋转,链接MethodHandles.)对于实际的类来说并不重要。它只想把String连接起来。
让我们试着用手来模仿这种行为。毕竟,引导方法是一个普通的Java方法:
public static void main(String[] args) throws Throwable {
CallSite cs = StringConcatFactory.makeConcatWithConstants(MethodHandles.lookup(),
"makeConcatWithConstants", MethodType.methodType(String.class, int.class),
"text + String: \u0001");
int x = 2;
String result = (String) cs.dynamicInvoker().invokeExact(x);
System.out.println(result);
x = 3;
result = (String) cs.dynamicInvoker().invokeExact(x);
System.out.println(result);
}( VM做了更多的事情,比如它会记住结果,不会再次调用引导方法,但是对于我们的小例子来说,这已经足够好了)。
在这一点上,我们可以查看一下引导方法是如何工作的。
结果是:您可以将VM配置为使用不同的策略。
它使用java.base中的特权位置来访问不复制数组的java.lang.String的包私有构造函数--如果之后不修改内容,这是安全的。
默认策略是MethodHandle链接。
好消息是:如果有人在某个时候写了一个更好的策略,你的程序就会从中受益--不需要重新编译。
发布于 2020-04-28 21:07:26
请参阅JVM规范
首先,未签名的indexbyte1和indexbyte2用于为当前类的运行时常量池构造索引(§2.6),.索引处的运行时常量池项必须是对动态计算的调用站点的符号引用(§5.1)。
方便地,javap已经查找常量池并对信息进行解码;结果是在行中的指令后面打印了一个注释。
14: invokedynamic #20, 0 // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;number #0是您已经发布的BootstrapMethods属性的索引。方法名称的含义取决于该引导方法。此外,还有类型描述符 (I)Ljava/lang/String;,因此这个特定的调用会消耗int并生成String。
运行时将发生什么取决于引用的引导方法。这种调用指的是static方法StringConcatFactory.makeConcatWithConstants(...),作为方式的一部分,字符串连接是用Java 9编译的。
这种方法的文档化告诉我们,invokedynamic指令中使用的方法名是无关的,BootstrapMethod属性的静态参数(即text + String: \u0001 )决定字符串格式。\u0001是“普通参数”(即int参数)的位置持有者。
https://stackoverflow.com/questions/61485900
复制相似问题