多态
- 事物 存在的多种形态
多态的前提
- 有
继承
关系 - 有方法
重写
有父类引用指向子类对象
多态成员访问特点
成员变量
- 编译看
左边
(父类),运行看左边
(父类)。
- 编译看
成员方法
- 编译看
左边
(父类),运行看右边
(子类)。动态绑定
- 编译看
静态方法
- 编译看
左边
(父类),运行看左边
(父类)。 - 静态和类相关,
算不上重写
,只是子类运行时覆盖了父类的静态方法,所以访问还是看父类。 - 只有
非静态成员方法
,编译看左边,运行看右边
。
- 编译看
父类引用指向子类对象,就是
向上转型
。- Animal a = new Dog();
指向子类对象的
父类引用
,强转成子类
类型,使用子类中特有的方法
。向下转型
。把一个父类对象赋给子类引用变量时,就需要进行强制类型转换。Animal a = new Dog(); Dog dog = (Dog)a;
引用变量的强制类型转换
引用变量
只能调用
它编译时类型
的方法,而不能调用
它运行时
类型的方法,即使他实际所引用的对象确实包含该方法。如果需要让这个引用变量调用它
运行
时类型的方法,则必须把它强制类型转换成运行时类型
。当进行强制类型转换时需要注意:
基本类型
之间的转换只能在数值类型之间进行
,这里所说的数值类型包括整型
,浮点型
,字符型
。但数值类型和布尔类型之间不能进行类型转换
。引用类型
之间的转换只能在具有继承关系
的两个类型之间进行,如果是两个没有任何继承关系
的类型,则无法进行类型转换
,否则编译时就会出现错误。如果试图把
一个父类实例转换成子类类型
,则这个对象必须实际上是子类实例才行
(即编译时为父类类型,而运行时类型是子类),否则将在运行时引发ClassCastException异常。
public class ConversionTest { public static void main(String[] args) { double d = 13.4; long l = (long)d; System.out.println(l); int in = 5; // 试图把一个数值类型的变量转换为boolean类型,下面代码编译出错 // 编译时候会提示: 不可转换的类型 // boolean b = (boolean)in; Object obj = "Hello"; // obj变量的编译类型为Object,Object与String存在继承关系,可以强制类型转换 // 而且obj变量实际上类型是String类型,所以运行时也可通过 String objStr = (String)obj; System.out.println(objStr); // 定义一个objPri变量,编译类型为Object,实际类型为Integer Object objPri = Integer.valueOf(5); // objPri变量的编译时类型为Object,objPri的运行时类型为Integer,Object与Integer存在继承关系 // 可以强制类型转换,而objPri变量实际上类型是Integer类型, // 所以下面代码运行时引发ClassCastException异常 String str = (String)objPri; } }
当把子类对象赋给父类引用变量时,称为向上转型(upcasting),向上转型总是可以成功的,因为子类是一种特殊的父类。这种转型只是表明这个引用变量的编译类型是父类,但实际执行它的方法时,依然表现出子类对象的行为方式。
使用instanceof运算符,可以判断是否可以成功转换,从而避免出现转换异常。
if (obj instanceof String){ String str = (String)obj; }
instanceof 运算符
instanceof运算符前一个操作数通常是一个
引用类型变量
,后一个操作数通常是一个类
,也可以是一个接口
,用于判断前面的对象是否是后面的类,或者其子类、实现类的实例
。instanceof运算符前面操作数的编译时类型要么与
后面的类相同
,要么与后面的类具有父子继承关系
,否则编译错误。public class InstanceofTest { public static void main(String[] args) { // 声明hello时使用Object类,则hello的编译类型是Object, // Object是所有类的父类, 但hello变量的实际类型是String Object hello = "Hello"; // String与Object类存在继承关系,可以进行instanceof运算。返回true。 System.out.println("字符串是否是Object类的实例:" + (hello instanceof Object)); System.out.println("字符串是否是String类的实例:" + (hello instanceof String)); // 返回true。 // Math与Object类存在继承关系,可以进行instanceof运算。返回false。 System.out.println("字符串是否是Math类的实例:" + (hello instanceof Math)); // String实现了Comparable接口,所以返回true。 System.out.println("字符串是否是Comparable接口的实例:" + (hello instanceof Comparable)); String a = "Hello"; // // String类与Math类没有继承关系,所以下面代码编译无法通过 // System.out.println("字符串是否是Math类的实例:" // + (a instanceof Math)); } }
instanceof运算符的作用:在进行强制类型转换之前,首先判断前一个对象是否是后一个类的实例,是否可以成功转换,从而保证代码健壮性。