父类类型(比如Mammal)的变量指向子类(比如Cat)创建的对象,使用该变量调用父类中一个*被子类重写*的方法(比如move方法),
则父类中的方法呈现出不同的行为特征,这就是多态。
创建一个父类:
public class Mammal{
Sring weight = "100KG";
public void move(){
System.out.println("正在快速移动");
}
}
创建一个子类:
public class Cat extends Mammal{
double weight = 100.0;
String name = "Tom";
public void eat(){
System.out.println("猫咪正在吃饭");
}
@Override
public void move(){
System.out.println("猫咪正在房顶上快速移动");
}
}
创建一个Test类,调用父类和子类中的方法:
public class Test{
public static void main(String [] args){
Cat cat = new Cat();//通常我们都这样调用一个方法:本类类型变量 = 本类创建的对象
cat.move();//这样无论是编译还是运行都调用的是本类(即Cat类)中的方法
/*
但还有一种情况,那就是即将要说的多态,即 父类类型变量 = 子类创建的对象
在基本数据类型一块,我们知道一个小范围、低精度的数据可以直接赋值给一个大范围、高精度的数据变量类型,
例如:
double x = 9;
9是整型,double是浮点型,double > int;
在Java的“类”中也存在类似的现象,那就是“多态”
*/
Mammal mammal = new Cat();//Mammal类型变量 = Cat类创建的对象
mammal.move();//因为变量类型为Mammal类类型,所以编译时调用的是父类(即Mammal类)中的move方法;
//又因为变量mammal指向的是子类创建的对象,所以执行时调用的是子类(即Cat类)中的move方法。
//因此此处输出的结果就是:
//猫咪正在房顶上快速移动
//这种编译和运行时调用的方法不一致的现象就叫“多态”,即多种行为状态
}
}
综上可以知道“多态”有三种特点:
1、编译和运行时类型不一致,否则一定不会产生多态(上面的Cat类中`Cat cat = new Cat();`就不是多态)
2、被父类类型变量调用的方法一定要被子类类型重写,否则也不会出现所谓的多态
3、格式:父类类型变量 = 子类创建的对象;(此时“子类创建的对象”又称为“上转型对象”)
其中上转型对象的特点是:
1、上转型对象只能调用被子类重写的方法,不能直接调用子类“新增”的属性和方法。
例如:上面Cat类中新定义的`String name = "Tom";`和eat()方法就不能被上转型对象调用
2、上转型对象如果必须调用子类“新增”的属性和方法,则必须进行下转型。
在基本数据类型中,我们知道一个大范围、高精度的数据要想赋值给一个小范围、低精度的数据变量类型,则必须进行强制类型转换,
例如:int x = (int)9.0; 9.0属于浮点型,x是整型变量,
所以mammal进行下转型:
Cat c = (Cat)mammal;
此时就可以调用子类(即Cat类)“新增”的属性和方法了,例如:
System.out.println("c.name"); //此时打印的就是:Tom
c.eat(); //此时输出的就是:猫咪正在吃饭
3、非上转型对象不能进行下转型,例如:
Mammal m = new Mammal();//不是多态,不是上转型对象
Cat cc = (Cat)m; //此种代码是错的,不能被执行
4、如果子成员变量和父成员变量的名字相同(类型不一定相同),则上转型对象调用的是父类中的变量
例如:父类(Mammal类)中的`Sring weight = "100KG";`和子类(Cat类)中的`double weight = 100.0;`
当调用weight变量时:
System.out.println(mammal.weight);//输出的是:100KG