Java面向对象的多态性
一. 概念
定义:多态可以理解为事物存在的多种体现形态,多态是在运行期间,判断引用实际类型,根据实际类型调用相应的方法。
举例:比如说人又男女之分,我们可以说男人是人,也可以说是男人。动物有猫、狗,我们可以说猫是动物,动物也是猫中的一种。
人:男人,女人
动物:猫,狗
猫 x = new猫();
动物 x = new猫();
二. 多态的体现形式
1. 父类的引用指向了自己子类的对象
2. 父类的引用可以接收子类的对象
三. 多态的前提
1. 必须是类与类之间有关系,要么继承,要么实现
2. 通常还有一个前提,存在覆盖
四. 多态的有点和缺点
1. 优点
A. 多态出现大大提高了程序的扩展性。
2. 缺点
A. 虽然提高扩展性,但是只能使用父类的引用访问父类中的成员,
不可预先使用子类。这是由于,子类在父类之后加载,此时还没有子类被加载,如果要使用子类中的成员,就必须使用强制类型转换,但是发生强制类型转换之前是一定发生过多态的。
注意:
1、一定不能将父类的对象转换成子类类型。
2、可转换的:父类引用指向自己子类的对象时,该引用可被提升,也可被强制转化。
3、多态自始至终均为子类对象在做变化。
/*分析:
1、定义一个动物类这个超类类型(抽象),含有一个吃饭的抽象方法
2、定义子类(如猫,狗等),含有自己的方法(猫:抓老鼠;狗:看家)
3、用多态实现子类方法
*/
abstract class Animal //抽象类
{
abstract void eat();
}
class Cat extends Animal //Cat继承父类Animal
{
//复写父类的抽象方法
void eat(){
System.out.println("吃鱼");
}
//定义自身
void catchM(){
System.out.println("抓老鼠");
}
}
class Dog extends Animal
{
//复写父类的抽象方法
void eat(){
System.out.println("啃骨头");
}
//定义自身功能
void kanJ(){
System.out.println("看家");
}
}
class DuoTaiTest
{
public static void main(String[] args)
{
Animal a1 = new Cat();//多态运用a2.eat();
Dosome(a1);
Cat c = (Cat)a1;
Dosome(c);
c.catchM();
Animal a2 = new Dog();
a2.eat();
Dosome(a2);
Dog d = (Dog)a2;
Dosome(d);
d.kanJ();
}
public static void Dosome(Animal a)
{
a.eat();
}
五. 在多态的中(父类引用指向子类对象)成员函数的特点
1. 在编译期间:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
2. 在运行时期:参阅对象所属的类中是否有调用的方法(包括父类继承过来的方法)。
3. 简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
六. 多态中(父类引用指向子类对象)成员变量的特点:无论编译和运行,都参考做左边。
七. 多态中(父类引用指向子类对象)静态成员方法特点:无论编译和运行,都调用左边
八. 多态中(父类引用指向子类对象)静态成员变量特点:无论编译和运行,都调用左边
publicclass PloyDemo
{
publicstaticvoid main(String[] args)
{
/*
编译通过
Zi z = new Zi();
z.method1();//覆盖父类的方法,调用的还是子类覆盖后的
z.method2();//覆盖父类的方法,调用的还是子类覆盖后的
z.method3();//子类特有的方法
*/
/*
整个程序编译失败,因为f.method3()在父类中不存在
Fu f = new Zi();
f.method1();//覆盖父类的方法,调用的还是子类覆盖后的
f.method2();//覆盖父类的方法,调用的还是子类覆盖后的
f.method3();//父类中没有这个方法,编译失败
*/
/*
调用的是父类的num,无论如何变化是否为静态,调用的都是父类的num
Fu f = new Zi();
System.out.println(f.num);
*/
/*
调用的是子类的num,无论如何变化是否为静态,调用的都是子类的num
Zi z = new Zi();
System.out.println(z.num);
*/
/*
子类引用指向子类对象,调用的是子类的
Zi z = new Zi();
z.method3();//调用的是子类的方法
*/
/*
method4()是父类静态的方法,调用的一直都是父类的
Fu f = new Zi();
f.method4();//调用的是父类的方法
*/
}
}
class Fu
{
staticintnum = 5;
void method1()
{
System.out.println("fu method_1");
}
void method2()
{
System.out.println("fu method_2");
}
staticvoid method4()
{
System.out.println("fu method_4");
}
}
class Ziextends Fu
{
staticintnum = 8;
void method1()
{
System.out.println("zi method_1");
}
void method3()
{
System.out.println("zi method_3");
}
static void method4()
{
System.out.println("zi method_4");
}
}
九. 应用练习
/*
需求:
电脑运行实例,
电脑运行基于主板。
*/
interface PCI
{
publicvoid open();
publicvoid close();
}
class MainBoard
{
publicvoid run()
{
System.out.println("mainboard run ");
}
//PCI p = new NetCard()//接口型引用指向自己的子类对象。
publicvoid usePCI(PCI p){
if(p!=null)
{
p.open();
p.close();
}
}
}
class NetCardimplements PCI
{
publicvoid open()
{
System.out.println("netcard open");
}
publicvoid close()
{
System.out.println("netcard close");
method();
}
}
class SoundCardimplements PCI
{
publicvoid open()
{
System.out.println("SoundCard open");
}
publicvoid close()
{
System.out.println("SoundCard close");
}
}
class DuoTaiDemo5
{
publicstaticvoid main(String[] args)
{
MainBoard mb =new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(new NetCard());
mb.usePCI(new SoundCard());
}
}