• jvm源码解读--20 结合jvm源码理解 java 设计模式 模板方法


    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. invokespecial init 是调用初始化方法,返回时候会消耗一个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. 那么调用 #2 Person.sleep父类的sleep方法,其中的参数是子类的man对象,那么实际上调用的就是子类的sleep方法
    3. 子类有一个JVM虚表,先排列父类方法,接着排列子类方法,如果子类重写父类方法sleep,那么子类的虚表的父类部分的sleep方法会设置为子类方法,从而执行的是子类方法,若未重写,则方法父类方法
  • 相关阅读:
    python获取豆瓣电影TOP250的所有电影的相关信息
    使用python批量获取excel的sheet名称
    第1章 初见网络爬虫
    时间序列--日期的范围、频率及移动
    时间序列--时间序列基础
    时间序列--日期和时间数据类型及工具
    绘图与可视化--pandas中的绘图函数
    绘图与可视化--matplotlib API入门
    pandas基础--层次化索引
    pandas基础--缺失数据处理
  • 原文地址:https://www.cnblogs.com/zytcomeon/p/14931342.html
Copyright © 2020-2023  润新知