/**
* 演示多态原理,注意加上下面的 JVM 参数,禁用指针压缩
* -XX:-UseCompressedOops -XX:-UseCompressedClassPointers
*/
public class Demo3_10 {
public static void test(Animal animal) {
animal.eat();
System.out.println(animal.toString());
}
public static void main(String[] args) throws IOException {
test(new Cat());
test(new Dog());
System.in.read();
}
}
abstract class Animal {
public abstract void eat();
@Override
public String toString() {
return "我是" + this.getClass().getSimpleName();
}
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("啃骨头");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("吃鱼");
}
}
1)运行代码
停在 System.in.read() 方法上,这时运行 jps 获取进程 id
2)运行 HSDB 工具
进入 JDK 安装目录,执行
java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB
进入图形界面 attach 进程 id
打开 Tools -> Find Object By Query
输入 select d from cn.itcast.jvm.t3.bytecode.Dog d 点击 Execute 执行
4)查看对象内存结构
点击超链接可以看到对象的内存结构,此对象没有任何属性,因此只有对象头的 16 字节,前 8 字节是
MarkWord,后 8 字节就是对象的 Class 指针
但目前看不到它的实际地址
可以通过 Windows -> Console 进入命令行模式,执行
mem 0x00000001299b4978 2
mem 有两个参数,参数 1 是对象地址,参数 2 是查看 2 行(即 16 字节)
结果中第二行 0x000000001b7d4028 即为 Class 的内存地址
6)查看类的 vtable
方法1:Alt+R 进入 Inspector 工具,输入刚才的 Class 内存地址,看到如下界面
…
因为普通成员方法需要在运行时才能确定具体的内容,所以虚拟机需要调用 invokevirtual 指令
在执行 invokevirtual 指令时,经历了以下几个步骤
先通过栈帧中对象的引用找到对象
分析对象头,找到对象实际的 Class
Class 结构中有 vtable
查询 vtable 找到方法的具体地址
执行方法的字节码
难度有点大,先放下。。。