目录
1.多态的定义
(1)对于继承关系,多态是同一个行为具有多个不同表现形式或形态的能力。即同一个父类方法在不同子类中具有不同的表现形式。
(2)对于接口实现,多态就是同一个接口,使用不同的实例而执行不同操作。
(3)多态是方法的多态,不是属性的多态。
(4)多态体现为子类对象赋值给父类引用变量,然后在运行时才表现出具体的子类特征。例如所有动物都会吃东西,但是每种动物吃的东西不一样。当我们面前有一只小动物时,我们只是把它当做动物看待,知道他会叫,但是具体是什么动物,怎么叫,只有他叫了才知道。
(5)多态包括编译时多态(静态多态)和运行时多态(动态多态)。编译时多态主要是指方法的重载,是在编译时多态性的体现,但它在运行时谈不上多态;而运行时多态指在程序运行时方法调用上产生的多态性,它是通过动态绑定(在程序执行期间判断其引用对象的实际类型并调用相应的方法)实现的,即我们通常所说的多态。
2.多态存在的三个条件
(1)继承:继承是多态的前提,没有继承关系就体现不出多态。
(2)重写:子类必须重写父类的方法,而不是直接调用父类的方法。
(3)父类引用指向子类对象(向上转型):子类实例化时把子类看成是父类进行实例化。
3.多态的使用格式:左父右子
无论是继承关系还是接口实现,都应该遵循左父右子,即把子类当做父类来看待。其中继承关系中的父类一般为抽象类,强制重写父类抽象方法,以满足重写条件。
//父类:动物
public abstract class Animal {
public abstract void eat();
}
//子类:狗
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
//子类:猫
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
//子类:鸡
public class Chicken extends Animal {
@Override
public void eat() {
System.out.println("鸡吃米");
}
}
下面我们用多态的实现方式和普通实现方式的写法作对比。
public static void main(String[] args) {
//普通的子类实例化
Dog dog = new Dog();
dog.eat();
Cat cat = new Cat();
cat.eat();
Chicken chicken = new Chicken();
chicken.eat();
System.out.println("=========");
//多态实现子类的实例化
Animal animal1 = new Dog();
animal1.eat();
Animal animal2 = new Cat();
animal2.eat();
Animal animal3 = new Chicken();
animal3.eat();
}
结果:
狗吃骨头
猫吃鱼
鸡吃米
=========
狗吃骨头
猫吃鱼
鸡吃米
4.多态中成员的访问特点
(1)成员变量
①直接访问:等号左边是谁
②间接访问:方法属于谁(不重写属于父类,重写后属于子类)
public class Father {
int age = 100;
public void getAge(){
System.out.println(age);
}
}
public class Son extends Father {
int age = 30;
@Override
public void getAge(){
System.out.println(age);
}
}
public static void main(String[] args) {
//多态的写法
Father son1 = new Son();
System.out.println(son1.age);
son1.getAge();
System.out.println("=====");
//普通写法
Son son2 = new Son();
System.out.println(son2.age);
son2.getAge();
}
结果:
100//父类age
30
=====
30//子类age
30
(2)成员方法:编译看左边,运行看右边
①编译看左边:若需要调用的方法只存在于子类中,则用多态的方式调用会报错。
②运行看右边:对于子类重写父类的方法,运行时会自动加载重写后的方法。
public class Father {
public void getAge(){
System.out.println("父类方法");
}
}
public class Son extends Father {
@Override
public void getAge(){
System.out.println("重写过的方法");
}
public void particular(){
System.out.println("子类特有的方法");
}
}
public static void main(String[] args) {
Father father = new Son();
//father.particular();//错误写法,父类中没有该方法,编译不通过
father.getAge();//运行时看右边是Son,因此是Son的getAge方法
}
5.对象的向下转型与 instanceof 关键字
针对上面的多态写法,如果我们定义了一个方法,此方法会接受参数为Father类,但是我们需要使用他子类中的特有方法该如何实现呢,此处就需要把Father向下转型为Son类。
public static void funSon(Father father){
//instanceof关键字:判断当前对象是否属于某个类,返回值为boolean类型
if(father instanceof Son) {//只有原本就是Son才能转为Son
Son son = (Son) father;//向下转型格式
son.particular();
}
}
//运行
public static void main(String[] args) {
Father father = new Son();
funSon(father);//此时father为子类对象,可以使用子类特有的方法
}
需要注意的是:
①必须保证创建对象的时候是要转型的子类,才能转型成该子类。
②如果转型对象原本不是该子类,就不能转为这个子类,否则运行时会报错。
6.使用多态的好处
(1)可替换性:多态对已存在代码具有可替换性。例如,多态对动物类适用,对其他任何动物,如猫,狗,也同样适用。
(2)可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。
(3)接口性:多态是父类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
(4)灵活性:它在应用中体现了灵活多样的操作,提高了使用效率。
(5)简化性:多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。