看到了这一行
  18: invokevirtual #6 // Method TestMain$Caller.call:(Ljava/lang/String;)V
  确实是发生了静态绑定,确定了调用了接收String对象作为参数的caller方法。
  重写方法的示例
public class TestMain {
public static void main(String[] args) {
String str = new String();
Caller caller = new SubCaller();
caller.call(str);
}
static class Caller {
public void call(String str) {
System.out.println("a String instance in Caller");
}
}
static class SubCaller extends Caller {
@Override
public void call(String str) {
System.out.println("a String instance in SubCaller");
}
}
}
  执行的结果为
  22:27 $ java TestMain
  a String instance in SubCaller
  上面的代码,Caller中有一个call方法的实现,SubCaller继承Caller,并且重写了call方法的实现。我们声明了一个Caller类型的变量callerSub,但是这个变量指向的时一个SubCaller的对象。根据结果可以看出,其调用了SubCaller的call方法实现,而非Caller的call方法。这一结果的产生的原因是因为在运行时发生了动态绑定,在绑定过程中需要确定调用哪个版本的call方法实现。
  验证
  使用javap不能直接验证动态绑定,然后如果证明没有进行静态绑定,那么说明进行了动态绑定。
22:27 $ javap -c TestMain
Compiled from "TestMain.java"
public class TestMain {
public TestMain();
Code:
0: aload_0
1: invokespecial #1                  // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new           #2                  // class java/lang/String
3: dup
4: invokespecial #3                  // Method java/lang/String."<init>":()V
7: astore_1
8: new           #4                  // class TestMain$SubCaller
11: dup
12: invokespecial #5                  // Method TestMain$SubCaller."<init>":()V
15: astore_2
16: aload_2
17: aload_1
18: invokevirtual #6                  // Method TestMain$Caller.call:(Ljava/lang/String;)V
21: return
}
  正如上面的结果,
  18: invokevirtual #6 // Method TestMain$Caller.call:(Ljava/lang/String;)V
  这里是TestMain$Caller.call而非TestMain$SubCaller.call,因为编译期无法确定调用子类还是父类的实现,所以只能丢给运行时的动态绑定来处理。