美文网首页
分派的简单理解

分派的简单理解

作者: 听歌闭麦开始自闭 | 来源:发表于2019-02-18 20:08 被阅读0次

    invokevirtual字节码

    在具体举例描述之前先描述invokevirtual字节码工作过程

    找到操作数栈顶的第一个元素所指向的对象的实际类型,记作C。
    在类型C中找到与常量中的描述符和简单名称都相符的方法。
         如果找到则进行访问权限的校验。
             如果通过则返回这个方法的直接引用,查询结束;
             如果不通过,则返回java.lang.IllegalAccessError异常。
        否则,按继承关系从下向上对C的各个父类进行第2步操作。
    如果没有找到合适的方法,抛出AbstractMethodError异常。
    

    以下判断均基于该字节码


    invokevirtual字节码.png

    分派

    Java语言的静态分派属于多分派类型;Java语言的动态分派属于单分派类型

    静态分派是由编译器指定的,编译器虽然能确定出方法的重载版本,但在很多情况下这个重载版本并不是"唯一的"。
    有显式的静态类型时,通过静态类型确认执行哪个重载方法
    没有显式的静态类型时,只能通过语言上的规则去理解和推断

    类型变化简单描述
    示例代码: Human man = new Man();  
    // "Human"称为变量的静态类型/外观类型   “Man” 则称为变量的实际类型
    
    // 实际类型变化
    Human man = new Man();
    man = new Woman();
    
    // 静态类型变化
    sr.sayHello((Man) man);
    sr.sayHello((Woman) man)
    

    静态分派

    可以理解为方法的入参与静态分派有关,静态分派决定了在方法重载时使用哪个运行。

    public class StaticDispatch {
    
        public void sayHello(Human guy) { System.out.println(1); }
    
        public void sayHello(Man guy) { System.out.println(2); }
    
        public void sayHello(Woman guy) { System.out.println(3); }
    
        // 输出结果为 1   2   1   3
        public static void main(String[] args) {
            Human man = new Man();
            Human woman = new Woman();
            StaticDispatch sd = new StaticDispatch();
            sd.sayHello(man);
            sd.sayHello((Man) man);
            sd.sayHello(woman);
            sd.sayHello((Woman) woman);
        }
    }
    
    abstract class Human {}
    
    class Man extends Human {}
    
    class Woman extends Human {}
    
    静态分派代码字节码.png

    动态分派

    invokevirtual字节码含义的体现,动态分派决定了在方法重写时使用哪个运行。

    public class DynamicDispatch {
        public static void main(String[] args) {
            Human man = new Man();
            man.sayHello();
            man = new Woman();
            man.sayHello();
    
            Human woman = new Woman();
            woman.sayHello();
        }
    }
    
    abstract class Human {
        protected abstract void sayHello();
    }
    
    class Man extends Human {
    
        @Override
        protected void sayHello() { System.out.println("man say Hello!"); }
    }
    
    class Woman extends Human {
    
        @Override
        protected void sayHello() { System.out.println("woman say Hello!"); }
    }
    
    动态分派代码字节码.png

    Java 自带类型的方法重载

    这个示例就是没有显式的静态类型,所以只能通过语言上的规则去理解和推断

    测试方法是:以char-> int -> long -> float -> double -> 包装类 ->Serializable -> Object -> 可变长参数的顺序尝试注释目标方法,然后运行看输出结果。
    如果在idea中则不需要运行测试,被调用的方法会高亮,通过观察就可以知道结果。

    public class Overload {
        public static void sayHello(Object arg) {
            System.out.println("Object");
        }
        public static void sayHello(int arg) {
            System.out.println("int");
        }
        public static void sayHello(long arg) {
            System.out.println("long");
        }
        public static void sayHello(float arg) {
            System.out.println("float");
        }
        public static void sayHello(double arg) {
            System.out.println("double");
        }
        public static void sayHello(char arg) {
            System.out.println("char");
        }
        public static void sayHello(char... arg) {
            System.out.println("char");
        }
        public static void sayHello(Character arg) {
            System.out.println("Character");
        }
        public static void sayHello(Integer arg) {
            System.out.println("Character");
        }
        public static void sayHello(Serializable arg) {
            System.out.println("Serializable");
        }
    
        public static void main(String[] args) {
            sayHello('c');
        }
    }
    

    相关文章

      网友评论

          本文标题:分派的简单理解

          本文链接:https://www.haomeiwen.com/subject/wcyzeqtx.html