zoukankan      html  css  js  c++  java
  • 方法重载与invokevirtual字节码指令的关系

    1、方法重载

    创建MyTest5类

    public class MyTest5 {
    
        public void test(Grandpa grandpa){
            System.out.println("grandpa");
        }
    
        public void test(Father father){
            System.out.println("father");
        }
        public void test(Son son){
            System.out.println("son");
        }
    
    
        public static void main(String[] args) {
            Grandpa g1 = new Father();
            Grandpa g2 = new Son();
    
            MyTest5 myTest5 = new MyTest5();
    
            myTest5.test(g1);
            myTest5.test(g2);
        }
    }
    
    
    
    class Grandpa{
    
    }
    
    class Father extends Grandpa{
    
    }
    
    class Son extends Father{
    
    }
    

      输出结果如下:

    2、方法的静态分派
    Grandpa g1 = new Father();
    以上代码,g1的静态类型是Grandpa,而g1的实际类型(真正的指向的类型)是Father
    我们可以得出这样一个结论:变量的静态类型是不会发生变化的,而实际类型则可以发生变化的(多态的一种体现),实际类型是在运行期方可确定。

    方法重载,是一种静态的行为,编译期就可以完全确定。

    所以MyTest5最终的输出结果两个都是grandpa

    使用jclasslib,调用两个test方法,使用的都是invokevirtual指令

    3、方法的动态分派机制

     创建MyTest6.java类

    package com.example.jvm.bytecode;
    
    public class MyTest6 {
    
        public static void main(String[] args) {
            Fruit apple = new Apple();
            Fruit orange = new Orange();
    
            apple.test();
            orange.test();
    
            apple = new Orange();
            apple.test();
        }
    
    }
    class Fruit{
        public  void test(){
            System.out.println("Fruit");
        }
    }
    
    class Apple extends Fruit{
    
        @Override
        public void test() {
            System.out.println("Apple");
        }
    }
    
    class  Orange extends Fruit{
        @Override
        public void test() {
            System.out.println("orange");
        }
    }
    

      输出结果如下:

    Apple
    orange
    orange

    使用jclasslib查看字节码

    可以看到apple.test() 对应的指令为 invokevirtual #6 <com/example/jvm/bytecode/Fruit.test>  在编译的时候使用的类型为Fruit,并不知道真正的类型为Apple

    方法的动态分派
    方法的动态分派涉及到一个重要概念: 方法接收者。
    invokevirtual字节码指令的多态查找流程(执行期)
    1、找到操作数栈顶的第一个元素,它所指向对象的实际类型
    2、在实际对象中找对应的方法(test()方法),检查访问类型是否可以访问,找到了就调用。如果没找到,继续往上找。

    比较方法重载(overload)与方法重写(overwrite),我们可以得到这样的结论
    方法重载是静态的,是编译器行为; 方法重写是动态的,是运行期行为。

  • 相关阅读:
    Shell Sort 希尔排序
    Quick Sort 快速排序
    Merge Sort 归并排序
    Insertion Sort
    Bubble Sort
    dubbo的异常栈问题
    IoC 容器
    .Net Core集成RabbitMQ
    .NET CORE Skywalking的集成
    制造业的信息化之路
  • 原文地址:https://www.cnblogs.com/linlf03/p/11107879.html
Copyright © 2011-2022 走看看