Java中的分派

首先需要理解一下静态类型和动态类型。找了很多资料,没有在java的书中找到关于这两种类型的具体定义,但是在C++的书中找到了下面的定义,这可能就是java被称为是 C++- 的原因之一吧。:)

静态类型与动态类型

  • 静态类型:不需要考虑表达式执行期的语义,仅从表达式的字面的形式就能够决定的类型,在编译期确定的变量类型,并且在运行期不会改变。
  • 动态类型:由一个左值表达式指出的左值的动态类型,是其所引用的对象的最狭义类型,在运行期决定具体的变量类型,可以在运行期改变。即:基类引用所引用的对象的实际类型。

左值和右值

按字面意思,通俗地说。以赋值符号 = 为界,= 左边的就是左值,= 右边就是右值。
比如:(1) int b = 3;(2) int a =b;第(2)行代码,a为左值,b为右值。
-
更深一层,可以将 L-value 的 L, 理解成 Location,表示定位,地址。将R-value 的 R 理解成Read,表示读取数据。现在的计算机数据放在内存。内存有两个很基本的属性:内存地址和内存里面放的数据。想象完全一样的箱子。每个箱子有个编号,用来区分到底是哪个箱子,箱子里面可以放东西。内存地址相当于箱子的编号,内存的数据,相当于箱子里面放的东西。
-
变量名编译之后,会映射成内存地址。看看a = b的含义。其实就是 将 “b地址内存里面的数据”,放到”a地址内存”中。
——百度百科

静态分派和动态分派

静态分派:

  • 依赖静态类型 确定方法执行版本的分派。[ 判断参数是什么类型]
  • 编译期发生。

动态分派:

  • 依赖实际类型 确定方法执行版本的分派。[ 判断实际对象是什么类型]
  • 向上转型后调用子类重写的方法。
  • 运行期(根据实际类型)决定。

静态分派示例:

/**
 * Create by zhaihongwei on 2018/4/8
 */
public class StaticDispatch {

    public void sayHello(People people) {
        System.out.println("你好,我是人!");
    }

    public void sayHello(China china) {
        System.out.println("你好,我是中国人!");
    }

    public void sayHello(American american) {
        System.out.println("你好,我是美国人!");
    }
}

/**
 * Create by zhaihongwei on 2018/4/8
 */
public class People {

}

/**
 * Create by zhaihongwei on 2018/4/8
 */
public class China extends People {

}

/**
 * Create by zhaihongwei on 2018/4/8
 */
public class American extends People{

}

测试类:

/**
 * Create by zhaihongwei on 2018/4/8
 */
public class Test {

    public static void main(String[] args) {
        StaticDispatch dispatch = new StaticDispatch();

        People people = new People();
        People china = new China();
        People american = new American();

        dispatch.sayHello(people);
        dispatch.sayHello(china);
        dispatch.sayHello(american); 
    }
}

测试结果:

你好,我是人!
你好,我是人!
你好,我是人!

动态分派示例:

/**
 * Create by zhaihongwei on 2018/4/8
 */
public class People {

    public void sayHello() {
        System.out.println("你好,我是人!");
    }
}

/**
 * Create by zhaihongwei on 2018/4/8
 */
public class China extends People {

    @Override
    public void sayHello() {
        System.out.println("你好,我是中国人!");
    }
}

/**
 * Create by zhaihongwei on 2018/4/8
 */
public class American extends People{

    @Override
    public void sayHello() {
        System.out.println("你好,我是美国人!");
    }
}

测试类:

/**
 * Create by zhaihongwei on 2018/4/8
 */
public class Test {

    public static void main(String[] args) {

        People people = new People();
        People china = new China();
        People american = new American();

        people.sayHello();
        china.sayHello();
        american.sayHello();
    }
}

测试结果:

你好,我是人!
你好,我是中国人!
你好,我是美国人!

结论:

从上面的例子看出,变量的动态类型(实际类型)是在运行期确定的,重载方法是根据参数静态类型选择对应方法,重写方法的调用是根据动态类型来调用的。即:JAVA中重载为静态风派,重写为动态分派。