多态
java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型与运行时类型不一致,就可能出现多态(Polymorphism)。
下面是一个范例:
class BaseClass { public int book = 6; public void base() { System.out.println("父类的普通方法"); } public void test() { System.out.println("父类被覆盖的方法"); }}public class SubClass extends BaseClass{ //重新定义一个book实例Field隐藏父类的book实例Field public String book= "轻量级javaee企业应用实战"; 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); sc.base(); sc.test(); BaseClass ploymophicBc = new SubClass(); System.out.println(ploymophicBc.book); //下面调用将执行从父类继承到的base方法 ploymophicBc.test(); //因为ploymophicBc 的编译时类型是BaseClass //BaseClass 类没有提供sub方法,所以下面代码编译出错 //ploymophicBc.sub(); }}
上面程序的main方法中显式创建了三个引用变量,对于前两个引用变量bc和sc,他们编译时和运行时类型完全相同,因此调用它们的Field和方法非常正常。第三个引用变量ploymophicBc则比较特殊,它编译时类型是BaseClass,而运行时类型是SubClass,当调用该引用变量的test方法时,实际执行的是SubClass类中覆盖后的test方法,于是出现多态。
因为子类其实是一种特殊的父类,因此java允许把一个子类对象直接赋给一个父类引用变量,无须任何类型转换,或者被称为向上转型(upcasting),向上转型由系统自动完成。
当把一个子类对象直接赋给父类引用变量时,其方法行为总是表现出子类方法的行为特征,而不是父类行为特征,这就会出现:相同类型的变量,调用同一个方法时呈现出多种不同的行为特征,这就是多态。对象的Field不具备多态性。
引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法。因此,编写java编码时,引用变量只能调用声明该变量时所用类里包含的方法。
通过引用变量来访问其它包含的实例Field时,系统总是识图访问它编译时类型所定义的Field,而不是它运行时类型所定义的Field。
引用类型的强制类型转换
类型转换运算符是小括号,类型转换运算符的用法是:(type)variable,这种用法可以将bariable变量转换成一个type类型的变量。当进行强制类型转换时需要注意:
》基本类型之间的转换只能在数值类型之间进行,包括整数型,字符型和浮点型。
》引用类型之间的转换只能在具有继承关系的两个类型之间进行,如果试图把一个父类实例转换成子类类型,则无法节能型类型转换,负责编译出错,如果试图把一个父类实例转换成子类类型,则把这个对象必须实际上是子类实例才行(即编译时类型为父类类型,而运行时类型是子类类型),否则将在运行时出现ClassCastException异常。用instanceof运算符来判断是否可以成功转换。