// 重载 public class Overload { public static void main(String[] args) { A a = new B(); // invokevirtual指令:A.func(int)和A.func(long)形成重载,但需要动态绑定 a.func(1); } } class A { void func(int i) { } void func(long i) { } } class B extends A { @Override void func(int i) { } }
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #2 // class me/zhongmingmao/basic/invoke/bind/B 3: dup 4: invokespecial #3 // Method me/zhongmingmao/basic/invoke/bind/B."<init>":()V 7: astore_1 8: aload_1 9: iconst_1 // 虚方法调用 10: invokevirtual #4 // Method me/zhongmingmao/basic/invoke/bind/A.func:(I)V 13: return LineNumberTable: line 6: 0 line 7: 8 line 8: 13 LocalVariableTable: Start Length Slot Name Signature 0 14 0 args [Ljava/lang/String; 8 6 1 a Lme/zhongmingmao/basic/invoke/bind/A; }
// 重写 public class Override { public static void main(String[] args) { C c = new C(); // C.func()的flags为:ACC_FINAL // JVM能确定目标方法只有一个,invokevirtual指令将采用静态绑定 c.func(); } } class C { final void func() { } }
C
final void func(); descriptor: ()V flags: ACC_FINAL Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 13: 0 LocalVariableTable: Start Length Slot Name Signature 0 1 0 this Lme/zhongmingmao/basic/invoke/bind/C;
Override
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #2 // class me/zhongmingmao/basic/invoke/bind/C 3: dup 4: invokespecial #3 // Method me/zhongmingmao/basic/invoke/bind/C."<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #4 // Method me/zhongmingmao/basic/invoke/bind/C.func:()V 12: return LineNumberTable: line 6: 0 line 7: 8 line 8: 12 LocalVariableTable: Start Length Slot Name Signature 0 13 0 args [Ljava/lang/String; 8 5 1 d Lme/zhongmingmao/basic/invoke/bind/C; }
interface Customer { boolean isVip(); } class Merchant { static final double ORIGINAL_DISCOUNT = 0.8d; public double discount(double originalPrice, Customer customer) { return originalPrice * ORIGINAL_DISCOUNT; } } class Profiteer extends Merchant { @Override public double discount(double originalPrice, Customer customer) { if (customer.isVip()) { // invokeinterface return originalPrice * priceDiscrimination(); // invokestatic } return super.discount(originalPrice, customer); // invokespecial } private static double priceDiscrimination() { return new Random() // invokespecial .nextDouble() // invokevirtual + ORIGINAL_DISCOUNT; } }
$ javap -v Profiteer Constant pool: #1 = Methodref #8.#30 // me/zhongmingmao/basic/Merchant."<init>":()V #2 = InterfaceMethodref #31.#32 // me/zhongmingmao/basic/Customer.isVip:()Z #3 = Methodref #11.#33 // me/zhongmingmao/basic/Profiteer.priceDiscrimination:()D #4 = Methodref #8.#34 // me/zhongmingmao/basic/Merchant.discount:(DLme/zhongmingmao/basic/Customer;)D ... #6 = Methodref #5.#30 // java/util/Random."<init>":()V #7 = Methodref #5.#36 // java/util/Random.nextDouble:()D
// -XX:CompileCommand=dontinline,*.outBound @Slf4j public class InvokeVirtual { public static void main(String[] args) { Passenger a = new Foreigner(); Passenger b = new Chinese(); long start = System.currentTimeMillis(); int count = 2_000_000_000; int half_count = count / 2; for (int i = 1; i <= count; i++) { Passenger c = (i < half_count) ? a : b; c.outBound(); } long end = System.currentTimeMillis(); // 超多态内存缓存(方法表):6700ms // 单态内联缓存:2315ms log.info("{}ms", end - start); } } abstract class Passenger { public abstract void outBound(); @Override public String toString() { return super.toString(); } } @Slf4j class Foreigner extends Passenger { @Override public void outBound() { } } @Slf4j class Chinese extends Passenger { @Override public void outBound() { } public void shopping() { } }
Passenger的方法表
索引 | 方法 | 备注 |
---|---|---|
0 | Passenger.toString() | 重写Object.toString() |
1 | Passenger.outBound() | 抽象方法,不可执行 |
Foreigner的方法表
索引 | 方法 | 备注 |
---|---|---|
0 | Passenger.toString() | 重写Object.toString() |
1 | Foreigner.outBound() | 重写Passenger.outBound() |
Chinese的方法表
索引 | 方法 | 备注 |
---|---|---|
0 | Passenger.toString() | 重写Object.toString() |
1 | Chinese.outBound() | 重写Passenger.outBound() |
2 | Chinese.shopping() | 购物 |
// -XX:CompileCommand=dontinline,*.outBound Passenger a = new Foreigner(); Passenger b = new Chinese(); long start = System.currentTimeMillis(); int count = 2_000_000_000; int half_count = count / 2; for (int i = 1; i <= count; i++) { Passenger c = (i < half_count) ? a : b; c.outBound(); } long end = System.currentTimeMillis(); // 超多态内存缓存(方法表):6700ms // 单态内联缓存:2315ms log.info("{}ms", end - start);