静态分配

静态方法会在类加载期就进行解析,而静态方法显然也是可以拥有重载版本的,选择重载版本的过程也是通过静态分派完成的。

public class StaticDispatch{

    public void sayHello(Human guy){
        System.out.println("hello,guy!");
    }
    public void sayHello(Man guy){
        System.out.println("hello,gentleman!");
    }
    public void sayHello(Woman guy){
        System.out.println("hello,lady!");
    }
    public static void main(String[]args){
        Human man=new Man();
        Human woman=new Woman();
        StaticDispatch sr=new StaticDispatch();
        sr.sayHello(man);
        sr.sayHello((Man)man);
        sr.sayHello((Woman) woman);
}
}

//结果

hello,guy!
hello,guy!
hello,gentleman!
hello,lady!

我们把上面代码中的“Human”称为变量的静态类型(Static Type),或者叫做的外观类型(Apparent Type),后面的“Man”则称为变量的实际类型(Actual Type),静态类型和实际类型在程序中都可以发生一些变化,区别是静态类型的变化仅仅在使用时发生,变量本身的静态类型不会被改变,并且最终的静态类型是在编译期可知的;而实际类型变化的结果在运行期才可确定,编译器在编译程序的时候并不知道一个对象的实际类型是什么。

所有依赖静态类型来定位方法执行版本的分派动作称为静态分派。静态分派的典型应用是方法重载静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的。 

下面的代码更适合演示在编译期间确实调用方法的版本

public class maintest {
    public static void sayHello(Object arg) {
        System.out.println("hello Object");
    }

    public static void sayHello(int arg) {
        System.out.println("hello int");
    }

    public static void sayHello(long arg) {
        System.out.println("hello long");
    }

    public static void sayHello(Character arg) {
        System.out.println("hello Character");
    }

    public static void sayHello(char arg) {
        System.out.println("hello char");
    }

    public static void sayHello(char... arg) {
        System.out.println("hello char……");
    }

    public static void main(String[] args) {
        sayHello('a');
    }
}

执行结果: 

//执行结果
hello char

对应字节码
         0: bipush        97
         2: invokestatic  #10                 // Method sayHello:(C)V
         5: return

这很好理解,'a'是一个char类型的数据,自然会寻找参数类型为char的重载方法,如果注释掉sayHello(char arg)方法,那输出会变为:

//hello int
//对应字节码

         0: bipush        97
         2: invokestatic  #9                  // Method sayHello:(I)V
         5: return

这时发生了一次自动类型转换,'a'除了可以代表一个字符串,还可以代表数字97(字符'a'的Unicode数值为十进制数字97),因此参数类型为int的重载也是合适的。

我们继续注释掉sayHello(int arg)方法,那输出会变为:

hello long

//对应字节码
         0: ldc2_w        #8                  // long 97l
         3: invokestatic  #10                 // Method sayHello:(J)V
         6: return

实际上自动转型还能继续发生多次,按照char->int->long->float->double的顺序转型进行匹配.

原文地址:https://www.cnblogs.com/snow-man/p/10609317.html