Java中的许多对象(一般都是具有父子类关系的父类对象)在运行时都会出现两种类型:编译时类型和运行时类型,例如:Person person = new Student();这行代码将会生成一个person变量,该变量的编译时类型是Person,运行时类型是Student。
说明一下编译时类型和运行时类型:
Java的引用变量有两个类型,一个是编译时类型,一个是运行时类型,编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,会出现所谓的多态。因为子类其实是一种特殊的父类,因此java允许把一个子类对象直接赋值给一个父类引用变量,无须任何类型转换,或者被称为向上转型,由系统自动完成。
引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法,因此,编写Java代码时,引用变量只能调用声明该变量所用类里包含的方法。与方法不同的是,对象的属性则不具备多态性。通过引用变量来访问其包含的实例属性时,系统总是试图访问它编译时类所定义的属性,而不是它运行时所定义的属性。
/**
* Description:
* <br/>Copyright (C), 2005-2008, Yeeku.H.Lee
* <br/>This program is protected by copyright laws.
* <br/>Program Name:
* <br/>Date:
* @author Yeeku.H.Lee kongyeeku@163.com
* @version 1.0
*/
class BaseClass
{
public int book = 6;
public void base()
{
System.out.println("父类的普通方法");
}
public void test()
{
System.out.println("父类的被覆盖的方法");
}
}
public class SubClass extends BaseClass
{
//重新定义一个book实例属性覆盖父类的book实例属性
public String book = "轻量级J2EE企业应用实战";
public void test()
{
System.out.println("子类的覆盖父类的方法");
}
public void sub()
{
System.out.println("子类的普通方法");
}
public static void main(String[] args)
{
//下面编译时类型和运行时类型完全一样,因此不存在多态
BaseClass bc = new BaseClass();
//输出 6
System.out.println(bc.book);
//下面两次调用将执行BaseClass的方法
bc.base();
bc.test();
//下面编译时类型和运行时类型完全一样,因此不存在多态
SubClass sc = new SubClass();
//输出"轻量级J2EE企业应用实战"
System.out.println(sc.book);
//下面调用将执行从父类继承到的base方法
sc.base();
//下面调用将执行从当前类的test方法
sc.test();
//下面调用将执行从当前类的sub方法
sc.sub();
//下面编译时类型和运行时类型不一样,多态发生
BaseClass ploymophicBc = new SubClass();
//输出 6 —— 表明访问的是父类属性
System.out.println(ploymophicBc.book);
//下面调用将执行从父类继承到的base方法
ploymophicBc.base();
//下面调用将执行从当前类的test方法
ploymophicBc.test();
//因为ploymophicBc的编译类型是BaseClass,BaseClass类没有提供sub方法
//所以下面代码编译时会出现错误。
//ploymophicBc.sub();
}
}