一个Java程序的执行要经过编译和执行(解释)这两个步骤,同时Java又是面向对象的编程语言。当子类和父类存在同一个方法,子类重写了父类的方法,程序在运行时调用方法是调用父类的方法还是子类的重写方法呢,这应该是我们在初学Java时遇到的问题。这里首先我们将确定这种调用何种方法实现或者变量的操作叫做绑定。(执行父类方法还是子类方法是由对象决定的,跟引用没有直接关系)
一:在Java中存在两种绑定方式,一种为静态绑定,又称作早期绑定。另一种就是动态绑定,亦称为后期绑定。
在处理java类中的成员变量时,并不是采用运行时绑定,而是一般意义上的静态绑定。所以在向上转型的情况下,对象的方法可以找到子类,而对象的属性还是父类的属性。
区别对比:
(1)静态绑定发生在编译时期,动态绑定发生在运行时
(2)使用private或static或final修饰的变量或者方法,使用静态绑定(其他的方法全部为动态绑定)。而虚方法(可以被子类重写的方法)则会根据运行时的对象进行动态绑定。
(3)静态绑定使用类信息来完成,而动态绑定则需要使用对象信息来完成。
(4)重载(Overload)的方法使用静态绑定完成,而重写(Override)的方法则使用动态绑定完成。
二:Java 技术安全模式要求在子类执行任何东西之前,描述父类的一个对象的各个方面都必须初始化。因此,Java 编程语言总是在执行子构造方法前调用父类构造方法的版本。有继承的类在运行的时候,一定要记得:初始化子类必先初始化父类,这是Java 程序的一个基本运行过程
上述类的基本运行顺序是:
- 先运行到第 8 行,这是程序的入口。
- 然后运行到第 9 行,这里要 new 一个 Test,就要调用 Test 的构造方法。
- 就运行到第 4 行,注意:初始化子类必先初始化父类。
- 要先初始化父类,所以运行到第 15 行。
- 然后是第 14 行,初始化一个类,必须先初始化它的属性。
- 然后是第 16 行。
- 然后是第 17 行,表示父类初始化完成。
- 然后是回到子类,开始初始化属性,因此运行到第 2 行,然后是第 3 行。
- 子类属性初始化完过后,才回到子类的构造方法,执行里面的代码,也就是第 5、6 行。
- 然后是第7 行,表示 new 一个 Test 实例完成。
- 然后回到 main 方法中执行第 10 行。
- 然后是第 11 行。
(2)声明父类的引用,执行的过程中调用的是子类的对象,程序首先寻找子类对象的method方法,但如果没有找到,于是向上转型去父类寻找
上例:由于子类重写了父类的method方法,根据上面的理论知道会去调用子类的getName方法去执行,因为子类对象有getName方法而没有向上转型去寻找
在处理java类中的成员变量时,并不是采用运行时绑定,而是一般意义上的静态绑定。所以在向上转型的情况下,对象的方法可以找到子类,而对象的属性还是父类的属性。
现在试图调用子类的成员变量age,该怎么做?最简单的办法是将该成员变量封装成方法getter形式。
三:Java继承机制的初始化顺序
结果:
执行顺序是: 父类的静态变量<=>父类的静态块->子类的静态变量<=>子类的静态
块(静态变量和静态块执行顺序是以它们在程序里出现的先后顺序来顺序执行的)
->(父类的实例化变量->父类的实例化块->)父类的构造函数
->(子类的实例化变量->子类的实例化块->)子类的构造函数
注:(1)静态区块的代码再类加载后初始化的时候执行,只执行一次;
(2)代码块(未使用static声明)在类实例化的时候执行;