// 重载
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);