详述多态
1、什么是多态?
在了解什么是多态之前,我们先来认识一下上转型对象。子类实例化的对象赋值给父类声明变量,则该对象称为上转型对象,这个过程称为对象上转型,对应于数据类型转换中的自动类型转换例如:double price = 10;
父类类型(比如Mammal)的变量(比如mammal)指向子类创建的对象这个子类创建的对象也称为上转型对象,使用该变量调用父类中一个被子类重写的方法(比如move方法),则父类中的方法呈现出不同的行为特征,这就是多态。
public class Mammal {
public void Move() {
System.out.println("正在移动......");
}
public class Whale extends Mammal{
@Override
public void Move() {
System.out.println("靠鱼鳍移动......");
}
}
public class Earth {
public static void main(String[] args) {
Whale whale = new Whale();
whale.Move();//当子类对象调用重写后的方法,调用的是子类重写后的方法
Mammal mammal = new Whale();//子类实例化的对象赋值给父类声明变量,则该对象称为上转型对象,这个过程称为对象上转型,对应于数据类型转换中的自动类型转换。new Whale()是上转型对象,父类类型变量指向子类创建的对象,等号左边编译时类型,右边运行时类型
mammal.Move();
}
}
2、怎么出现多态?
Java引用变量有两种类型,分别是编译时类型和运行时类型:编译时类型由声明该变量时使用的类型决定;运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓多态。
上转型对象调用被重写的方法,调用的是重写后的方法。因为mammal是父类类型变量但指向子类创建的对象,所以变量mammal编译时类型是父类类型Mammal,运行时类型是子类类型Whale。
3、上转型对象不能调用子类新增的方法和属性
public class Mammal {
public void Move() {
System.out.println("正在移动......");
}
}
public class Whale extends Mammal{
double weight = 10000;
@Override
public void Move() {
System.out.println("靠鱼鳍移动......");
}
public void Breath() {
System.out.println("正在呼吸");
}
}
public class Earth {
public static void main(String[] args) {
Mammal mammal = new Whale();//自动类型转换(对象上转型)new Whale()是上转型对象,父类类型变量指向 子类创建的对象,等号左边编译时类型,右边运行时类型
mammal.Move();//两个状态:表面上调用的是父类的方法,但执行时由于mammal存的是子类创建的对象,所以执行时执行的是子类中方法
mammal.Breath();//上转型对象不能调用子类新增方法和属性
mammal.weight = 12000
}
}
因为mammal编译时类型是父类类型,而父类中没有属性weight和方法breath(),所以程序在编译时就会报错。
4、怎么利用上转型对象调用新增的属性和方法?
对象上转型利用下转型调用新增的属性和方法,下转型的前提上转型。
public class Mammal {
public void Move() {
System.out.println("正在移动......");
}
}
public class Whale extends Mammal{
double weight ;
@Override
public void Move() {
System.out.println("靠鱼鳍移动......");
}
public void Breath() {
System.out.println("正在呼吸");
}
}
public class Earth {
public static void main(String[] args) {
Mammal mammal = new Whale();
//上转型对象如何调用新增的属性和方法,使用下转型
Whale whale = (Whale)mammal;
whale.Breath();
whale.weight = 12333.255;
System.out.println(whale.weight);
// Mammal mammal = new Mammal();
// Whale whale = (Whale)mammal;//不能称为下转型,因为mammal不是上转型对象,下转型前提是先出现上转型对象
}
}
程序中的注释符去掉将会报错 Mammal mammal = new Mammal();
Whale whale = (Whale)mammal;
因为new Mammal()不是上转型对象,无法进行下转型。
5、上转型对象调用被子类覆盖的属性时,调用的是父类的属性
public class Mammal {
public String weight = "1t";
public void Move() {
System.out.println("正在移动......");
}
}
public class Whale extends Mammal{
double weight = 1000;
@Override
public void Move() {
System.out.println("靠鱼鳍移动......");
}
public void Breath() {
System.out.println("正在呼吸");
}
}
public class Earth {
public static void main(String[] args) {
Mammal mammal = new Whale();
System.out.println(new Whale().weight);
System.out.println(mammal.weight);//上转型对象调用被子类覆盖的属性,调用的是父类的属性
}
}
总而言之,上转型对象调用父类的方法,如果方法已被子类重写,则表现为子类的行为特征,否则表现为父类的行为特征。
上转型对象调用父类的成员变量,无论该成员变量是否被子类覆盖,使用的都是父类的成员变量
6、在多态的前提下,父类中被子类重写的方法没有必要有方法体
父类中没有方法体的方法称为抽象方法,只要有一个抽象方法的类称为抽象类,所有的方法都是抽象方法的类称为接口。
public class Mammal {
public void Move() {
}
}
public class Whale extends Mammal{
@Override
public void Move() {
System.out.println("靠鱼鳍移动......");
}
}
public class Earth {
public static void main(String[] args) {
Whale whale = new Whale();
whale.Move();
}
}
注意:
如果编译时类型和运行时类型相同,则一定不会出现多态
如果编译时类型和运行时类型不同,也不一定会出现多态
第一句话很好理解,第二句话的意思是及时编译时类型和运行时类型不同,上转型对象调用的方法也不一定被重写,这时,也不会出现多态。