write by 张艳涛
前言:
在学习jvm之前,看过设计模式的书,知道模板方法的设计模式,今天在看java并发编程的艺术里面关于AbstractQueuedSynchronizer 用法,这个就使用了模板方法了,开始没注意到,回想过去的设计模式的知识,才看清楚了,那么模板方法的原理是什么呢?结合jvm虚拟机原理? 我想答案是多态
那么,现在写一篇分析过程,来解析这个过程
新进一个Man类 和一个Person类
package com.zyt.java_concurrency_in_practice.templatemode;
public class Man extends Person{
@Override
protected void sleep() {
System.out.println("子类在执行 Sleep~~~~");
}
public static void main(String[] args) {
Man man = new Man();
man.sayHi();
}
}
//=========
package com.zyt.java_concurrency_in_practice.templatemode;
public abstract class Person {
protected void sleep(){
System.out.println("父类,在执行sleeping 方法");
};
protected void sayHi(){
sleep();
}
}
打印执行结果
子类在执行 Sleep~~~~
Process finished with exit code 0
这个问题关键点是在父类方法里面的sleep()方法是子类的方法,不是父类的sleep方法!!!
关键点是调用方法,会有一个this对象的参数,比如说 子类对象.function() ;那么 this 就是子类对象,static 方法 没有this对象
那么就来解析模板方法的实现原理
public static void main(String[] args) {
Man man = new Man();
man.sayHi();
}
==========================================
0 new #5 <com/zyt/java_concurrency_in_practice/templatemode/Man>
3 dup
4 invokespecial #6 <com/zyt/java_concurrency_in_practice/templatemode/Man.<init>>
7 astore_1
8 aload_1
9 invokevirtual #7 <com/zyt/java_concurrency_in_practice/templatemode/Man.sayHi>
12 return
逐句分析
1、 编号0的第一句是新建对象man,现在这个man对象在操作数栈上;
2、 dup是在操作数栈上复制man对象;
3、 invokespecialinit是调用初始化方法,返回时候会消耗一个dup出来的man对象;
4、 编号7将man对象存储在本地变量表里面;
5、 编号8将位置为1的变量加载到操作数栈上;
6、 编号9调用Man.sayHi方法;
进入到父类方法执行
public abstract class Person {
protected void sleep(){
System.out.println("父类,在执行sleeping 方法");
};
protected void sayHi(){
sleep();
}
}
//===============sayHi()==========
0 aload_0
1 invokevirtual #2 <com/zyt/java_concurrency_in_practice/templatemode/Person.sleep>
4 return
调用新方法,会准备新的栈结构,而且会服用操作数栈,和本地变量表
这里的话,应该会将子类的操作数栈中的man对象,复用为父类方法的本地变量表变量
1、 那么编号为0的aload_0就是加载子类的man对象(在本地变量表中),到新的操作数栈;
- 那么调用 #2 Person.sleep父类的sleep方法,其中的参数是子类的man对象,那么实际上调用的就是子类的sleep方法
3、 子类有一个JVM虚表,先排列父类方法,接着排列子类方法,如果子类重写父类方法sleep,那么子类的虚表的父类部分的sleep方法会设置为子类方法,从而执行的是子类方法,若未重写,则方法父类方法;