谈论“多态”需要首先涉及“前期绑定”和“后期绑定”。
一、前期绑定
1.1、概念
在编译期,完成前期绑定。
1.1.1、“实例对象访问成员”形式的前期绑定
实例对象访问成员,参见如下示例代码:
package chapter8;
public class A {
static int b = 20;
int a = 10;
static int g() {
return 40;
}
int f() {
return 30;
}
public static void main(String[] args) {
A a = new A();
System.out.println(a.a);
System.out.println(a.b);
System.out.println(a.f());
System.out.println(a.g());
}
}
前期绑定描述:
- 确定实例对象对应的声明Java类(注意不是实例对象对应的实际Java类),基于该声明Java类的实际定义进行访问成员的绑定
- 当该声明Java类的实际定义中含有0个匹配的候选项时,前期绑定失败,编译报错;当该声明Java类的实际定义中含有大于0个匹配的候选项时,依据一定的策略进行选取绑定(笔者不在这里探讨详细的策略),比如“原生成员优先级高于继承成员”,如果由于“违反约束条件”等原因导致不能顺利选取绑定则前期绑定失败,编译报错,否则前期绑定成功
1.1.2、“直接通过类访问成员”形式的前期绑定
直接通过类访问成员,参见如下示例代码:
package chapter8;
public class A {
static int b = 20;
int a = 10;
static int g() {
return 40;
}
int f() {
return 30;
}
public static void main(String[] args) {
System.out.println(A.b);
System.out.println(A.g());
}
}
前期绑定描述:
- 基于所使用Java类的实际定义进行访问成员的绑定
- 当该使用Java类的实际定义中含有0个匹配的候选项时,前期绑定失败,编译报错;当该使用Java类的实际定义中含有大于0个匹配的候选项时,依据一定的策略进行选取绑定(笔者不在这里探讨详细的策略),比如“原生成员优先级高于继承成员”,如果由于“违反约束条件”等原因导致不能顺利选取绑定则前期绑定失败,编译报错,否则前期绑定成功
1.2、几个例子
1.2.1、例子1
package chapter8;
public class Polymorphic1 extends A1 {
int a = 20;
public static void main(String[] args) {
A1 a1 = new Polymorphic1();
//结果为10
System.out.println(a1.a);
}
}
class A1 {
int a = 10;
}
1.2.2、例子2
package chapter8;
public class Polymorphic2 extends A3 {
public static void main(String[] args) {
Polymorphic2 polymorphic2 = new Polymorphic2();
//结果为30
System.out.println(polymorphic2.a);
}
}
class A2 {
int a = 10;
}
class A3 extends A2 {
int a = 30;
}
1.2.3、例子3
package chapter8;
interface A5 {
int a = 40;
}
public class Polymorphic3 extends A4 implements A5 {
public static void main(String[] args) {
Polymorphic3 polymorphic3 = new Polymorphic3();
//提示: Reference to 'a' is ambiguous, both 'A4.a' and 'A5.a' match
System.out.println(polymorphic3.a);
}
}
class A4 {
int a = 10;
}
1.2.4、例子4
package chapter8;
public class Polymorphic9 extends A15 {
public static void main(String[] args) {
//结果为10
System.out.println(Polymorphic9.a);
}
}
class A15 {
static int a = 10;
}
二、后期绑定
2.1、概念
在运行期,完成后期绑定。
后期绑定只针对“一般方法”成员,因此只有“实例对象访问成员”形式的后期绑定。
后期绑定描述:
- 需要特别注意的是,在后期绑定之前已经完成了前期绑定,如果后期绑定未作重新绑定,则使用前期绑定的结果
- 确定实例对象对应的实际Java类,基于该实际Java类的实际定义查找覆盖欲访问一般方法的方法
- 当该实际Java类的实际定义中含有0个匹配的候选项时,后期绑定未作重新绑定,使用前期绑定的结果,运行不报错;当该实际Java类的实际定义中含有大于0个匹配的候选项时,依据一定的策略进行选取绑定(笔者不在这里探讨详细的策略),比如“必须是非虚方法”,“原生一般方法优先级高于继承一般方法”等,如果由于“违反约束条件”等原因导致不能顺利选取绑定则后期绑定失败,运行报错,否则后期绑定成功,后期绑定作重新绑定
2.2、几个例子
2.2.1、例子1
package chapter8;
public class Polymorphic4 extends A6 {
public static void main(String[] args) {
Polymorphic4 polymorphic4 = new Polymorphic4();
//结果为20
System.out.println(polymorphic4.f());
}
int f() {
return 20;
}
}
abstract class A6 {
abstract int f();
}
2.2.2、例子2
package chapter8;
public class Polymorphic5 extends A8 {
public static void main(String[] args) {
A7 a7 = new Polymorphic5();
//结果为30
System.out.println(a7.f());
}
int f() {
return 30;
}
}
class A7 {
int f() {
return 10;
}
}
class A8 extends A7 {
int f() {
return 20;
}
}
2.2.3、例子3
package chapter8;
interface A9 {
int f();
}
public class Polymorphic6 extends A10 {
public static void main(String[] args) {
Polymorphic6 polymorphic6 = new Polymorphic6();
//结果为30
System.out.println(polymorphic6.f());
}
}
class A10 implements A9 {
public int f() {
return 30;
}
}
2.2.4、例子4
package chapter8;
interface A12 {
int f();
}
public class Polymorphic7 extends A11 implements A12 {
public static void main(String[] args) {
Polymorphic7 polymorphic7 = new Polymorphic7();
//结果为30
System.out.println(polymorphic7.f());
}
}
class A11 {
public int f() {
return 30;
}
}
2.2.5、例子5
package chapter8;
public class Polymorphic8 {
public static void main(String[] args) {
Polymorphic8 polymorphic8 = new A13();
//结果为40
System.out.println(polymorphic8.f());
//结果为30
A13 a13 = new A13();
System.out.println(a13.f());
}
private int f() {
return 40;
}
}
class A13 extends Polymorphic8 {
/**
* 未继承覆盖Polymorphic8中的“int f()”方法,因此关于该一般方法无后期绑定
*/
int f() {
return 30;
}
}
综上,多态的本质为:访问“一般方法”成员,后期绑定可以改变前期绑定的结果。