多态
- 事物 存在的多种形态
多态的前提
- 有
继承
关系 - 有方法
重写
有父类引用指向子类对象
多态成员访问特点
成员变量
- 编译看
左边
(父类),运行看左边
(父类)。
- 编译看
成员方法
- 编译看
左边
(父类),运行看右边
(子类)。动态绑定
- 编译看
静态方法
- 编译看
左边
(父类),运行看左边
(父类)。 - 静态和类相关,
算不上重写
,只是子类运行时覆盖了父类的静态方法,所以访问还是看父类。 - 只有
非静态成员方法
,编译看左边,运行看右边
。
- 编译看
父类引用指向子类对象,就是
向上转型
。- Animal a = new Dog();
指向子类对象的
父类引用
,强转成子类
类型,使用子类中特有的方法
。向下转型
。把一个父类对象赋给子类引用变量时,就需要进行强制类型转换。1
2Animal a = new Dog();
Dog dog = (Dog)a;
引用变量的强制类型转换
引用变量
只能调用
它编译时类型
的方法,而不能调用
它运行时
类型的方法,即使他实际所引用的对象确实包含该方法。如果需要让这个引用变量调用它
运行
时类型的方法,则必须把它强制类型转换成运行时类型
。当进行强制类型转换时需要注意:
基本类型
之间的转换只能在数值类型之间进行
,这里所说的数值类型包括整型
,浮点型
,字符型
。但数值类型和布尔类型之间不能进行类型转换
。引用类型
之间的转换只能在具有继承关系
的两个类型之间进行,如果是两个没有任何继承关系
的类型,则无法进行类型转换
,否则编译时就会出现错误。如果试图把
一个父类实例转换成子类类型
,则这个对象必须实际上是子类实例才行
(即编译时为父类类型,而运行时类型是子类),否则将在运行时引发ClassCastException异常。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public 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运算符,可以判断是否可以成功转换,从而避免出现转换异常。
1
2
3if (obj instanceof String){
String str = (String)obj;
}
instanceof 运算符
instanceof运算符前一个操作数通常是一个
引用类型变量
,后一个操作数通常是一个类
,也可以是一个接口
,用于判断前面的对象是否是后面的类,或者其子类、实现类的实例
。instanceof运算符前面操作数的编译时类型要么与
后面的类相同
,要么与后面的类具有父子继承关系
,否则编译错误。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public 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运算符的作用:在进行强制类型转换之前,首先判断前一个对象是否是后一个类的实例,是否可以成功转换,从而保证代码健壮性。