动态调用instructionน指令instructionอิมพลีเมนต์เพิ่มเข้ามาในJava 7(JVM)动态บนJVMเช่นJRuby,Groovy(เราเลยไม่ค่อยได้ใช้เท่าไร)ซึ่งแต่ Reflectionอในimplementองใช้java Reflectionในการ实现方法调用call performaceที่ต่ำเนื่องจากว่าJVMจะ优化ลำบาก
์อมไพเลอร์Javac版本7จะยังไม่มีการ编译ที่ให้ผลลัพธ์ที่เป็น动态调用 ออกมา ภาษาจาวาเองเริ่มนำ 动态调用 มาใช้ในเวอร์ชัน 8
背景 JVM จะมี instruction ที่ใช้ในการเรียก method ที่แตกต่างกันดังนี้invokespecialกรับเรหยก实例私有方法หรือ构造函数(非虚拟)invokestatic静态方法invokevirtual实例方法ที่เป็นvirtualพวก受保护的,公共的,默认可见性invokeinterfaceสำหรับเรียก接口虚拟方法vir지เหตที่มีinvokevirtualและinvokeinterfaceเพราะว่าinvokervirtualคอมไพล์เลอร์จะรู้ตำเหน่งของ方法 ไม่ได้ปล。 虚拟术语虚拟术语术语C ++的++นภาษาแรแนะะร์ครับ
dynamicให้งมีdynamic dynamic dynamic constant constant constant constant constantได้ได้ได้ได้ได้ได้ได้ได้ได้ได้ได้ได้
- CONSTANT_MethodHandle_infoเป็น数据结构ที่เอาไว้解析引用ังยังinvokespectal,invokestatic,invokevirtual,invokeintervaceในภาษาจาวาจะ代表โดยjava.lang.invoke.MethodHandleCONSTANT_MethodType_infoเอาไว้เป็น类型描述符ของ方法(参数และ返回类型)ในภาษาจาวาวาจะ表示โดยjava.lang.invoke.MethodTypeCONSTANT_InvokeDynamic_infoไว้อาไว้解析参考referenceยัง引导方法และ可选参数ยังไม่ต้องสนใจในตอนนี้
Stringรับในบทความนี้เราจะมาเขียนจาวาให้ทำกาให้ทำการให้ทำกรียก方法String.concat(String)CONSTANT_MethodHandleและCONSTANT_MethodTypeconstantาทยังไงใน常量池โดยใช้Java API
อ่านคำอธิบายจาก评论เอานะครับ
สำหรับใครที่ยังอ่าน bytecode ไม่ออก ผมมีบทความเก่าอยู่ ลองอ่านดูนะครับ
JVM 1
JVM 2
JVM 3
package th.co.geniustree.indy;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class MethodHandleTest {
public static void main(String[] args) throws Throwable {
//Lookup เป็น Factory สำหรับเอาไว้สร้าง MethodHandle
final MethodHandles.Lookup lookup = MethodHandles.lookup();
// เราจะอธิบายว่าเราต้องการ method ที่มี return type เป็นอะไร และ param เป็นอะไร
//ในที่นี้เราจะเรียก String.concat(String)
//กรณีที่ compiler เป็นคนจัดการให้ ตรงนีจะเป็น CONSTANT_MethodType
//CONSTANT_MethodType --> (Ljava/lang/String;)Ljava/lang/String;
//โดย L className ; เป็น field descriptor L หมายถึง reference type ใดๆ ส่วน className จะแทน . ด้วย /
MethodType returnStringAndStringParamMethosType = MethodType.methodType(String.class, String.class);
// สร้าง MethodHandle เพื่อห่อหุ่มเอา invokevirtual java/lang/String.concat:(Ljava/lang/String;)Ljava/lang/String; เอาไว้สำหรับ invoke
//ขั้นตอนนี้จะทำการ access checking ด้วยว่ามีสิทธิเข้าถึงไหม ซึ่งจะต่างจาก Reflection ตรงที่ reflection จะ check ทุกครั้งที่ invoke method ดังนั้นตรงนี้ MethodHandle จะเร็วกว่า
// เพราะโดยปกติแล้ว lookup.findXxx จะทำครั้งเดียวแล้วเก็บ method handle instance เอาไว้ invoke()
MethodHandle concatMethodHandle = lookup.findVirtual(String.class, "concat",returnStringAndStringParamMethosType);
//ถ้าเป็น bytecode ก็จะเทียบเท่ากับ
//ldc "Hello" --> push "Hello" reference to operand stack
//ldc "World" --> push "World" reference to operand stack
//invokevirtual java/lang/String.concat:(Ljava/lang/String;)Ljava/lang/String;
final String result = (String) concatMethodHandle.invokeExact("Hello", "World");
System.out.println(result); // print "HelloWorld"
}
}