黑马程序员_面向对象(多态)

来源:互联网 发布:淘宝网沙发垫 编辑:程序博客网 时间:2024/05/21 14:47

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 

面向对象(多态)

多态概念

多态:可以理解为事物存在的多种体现形态。现实生活中的事物来说,猫,即是猫也是动物,一个人是男人也是人。就是说一个事物可以以不同形态来描述和表示,这就可以理解为多态。程序中,函数的重载性也是一种多态,同一个函数名在类中存在多个函数,但是具体体现方式不一样。

举例来说,比如:动物,都具有吃的行为,但每种动物吃的东西都不一样,所以可以定义成抽象。猫,是动物的一种,它吃鱼,这就是把动物吃的行为具体的实现了(程序上体现是implement父类),同时它有自己的特有的行为,抓老鼠。狗,也是动物的一种,它吃骨头,也实现了动物中吃的行为,也有自己特有的属性,看家。看下图:                          

  

 

我们调用每个动物的吃的行为,通过建立每个动物的对象即可调用。但注意看,每个动物都继承了动物父类,那么我们就可以通过这个形式来进行引用:

                    父类名 名称 =  new 子类名();

这就是多态的体现。

     具体来说就是:父类的引用指向了子类的对象父类的引用也可以接受自己子类的对象。这样,其实也就是提高了程序的拓展性,子类只要继承或实现父类,并覆盖父类方法,那么就可以被父类引用所指向。比如程序中,一个函数可以接受猫这个对象,这个函数中可以实现子类吃的方法,那如果接受狗这个对象,就得在建立一个函数,这样程序就比较冗长而且死板,之后又更多父类的是动物的其他子类动物类进来,那岂不是建立更多的对象?所以,可以把接受的子类对象改为接受一个父类的引用,就是程序里接受一个动物类的引用。因为父类引用指向子类对象,所以我们可以向函数里传递不同的子类对象,如果之后又新的子类对象加进来,只需继承父类并覆盖父类方法即可,这样就提高了程序的拓展性。

但是,要注意的是,父类引用只能使用父类中的成员,通俗来讲,父类的引用指向子类对象,在父类应用调用方法时,只能调用子类已覆盖父类方法的方法,如果子类中有自己特有方法,运用父类引用调用时就会出错。那上述动物,猫,和狗来说,父类中只有一个方法,那就是吃,猫和狗覆盖了吃的方法,所以动物的引用就能调用子类中吃的方法,而不能调用猫和狗中特有方法(抓老鼠和看家)。

 

总结的来说:

 

1) 多态体现在:父类引用指向子类对象,父类引用接受子类对象

2) 多态的前提:类与类之间有继承或是实现的关系

3) 多态的前提:子类中必须存在覆盖,而且父类引用调用只能调用覆盖的方法和父类成员

4) 多态提高了程序的拓展性,因为可以往里添加其他子类模块

5) 多态弊端:就是只能使用父类的引用方法父类中的成员

 

多态的应用

看一个程序:

abstract class Animal {

         abstractvoid eat();

}

class Catimplements Animal  {

         publicvoid eat(){

                   执行语句(吃鱼);

         }

         publicvoid catchMouse(){

                   执行语句(抓老鼠);

         }

}

我们在使用多态的时候,会有这样的语句:

                   Animal  a = new Cat();

其实这样做,是做了自动类型提升的动作,称为向上转型,这样我们就可以用父类中的成员。但我们相拥猫中的特有方法时该怎么操作,如果再建立一个对象时,那就是另一只猫了。这里,我们就向下转型,准确来说是强制将父类的引用转成子类类型。程序就改变了:

                   Cat   c  =(Cat) a;

这样就可以使用子类的特有方法了:

                   c.catchMouse();

但要注意一点,如果建立父类的对象,那么就不能向下转型,因为猫一定是动物,而动物一定是猫,也可能是其他动物,程序如下:

                     Animal  a = new Animal();

                     Cat  c = (Cat) a;---------------------à这样是错误的

这里要注意,我们用的一是对象的引用,仅是引用,二是至始至终都是子类对象在变化,不管是自动向上转型,还是手动向下转型。

 

在看一个示例:

      publicstatic void function(Animal a ) {

                            a.eat();

}

在这个方法中,可以传入子类对象,然后用父类成员,但是想在这个方法中用到子类特有的方法,那就得向下转型。由于我们不知道会传入什么样的子类对象,所以要先进行判断。这样就用到了又一个关键字:instanceof 意思是a是否是 b类型的。所以上面程序可加入:

                                 if(a instanceof Cat){

     Catc =(Cat)a;

     c.catchMouse();

}

总结:

1)  父类引用指向子类对象,会自动提升子类类型,叫向上转型

2)  父类引用指向子类对象,可以向下转型,父类自己的对象不可以向下转型。

3)  注意,向上转型和向下转型都是子类在变化

4)  新关键字instanceof  判断一个引用是否是另一引用类型。

 

 

1、在多态中成员函数(非静态的)的特点:

编译时期:参阅引用型变量所属类中是否有调用的方法,如果有,编译通过,若没有编译失败。

运行时期:参阅对象所属类中是否有调用方法。

简单来说,就是编译看左边,运行看右边。

2、在多态中成员变量的特点:

无论运行和编译,都参考左边(引用型变量所属类)。

3、在多态中静态成员函数特点:

无论运行和编译,都参考左边。

 

看一个实例程序:

interface PCI  //定义一个PCI接口,指定规则

{

         publicvoid open();

         publicvoid close();

}

class MainBorad

{

         voidrun(){

                   System.out.println("mainboradrun");

         }

         publicvoid usePCI(PCI p){ //使用PCI接口

                   p.open();

                   p.close();

         }

}

class NetCard implements PCI //符合PCI接口规则,程序上对里面的方法进行复写

{

         publicvoid open(){

                   System.out.println("netcardopen");

         }

         publicvoid close(){

                   System.out.println("netcardopen");

         }

}

class Test

{

         publicstatic void main(String[] args){

                   MainBordm = new MainBorad();

                   m.run();

                   m.show(newNetCard());//调用的时候,传入necard对象,这里实现了多态

         }

}

 

上述程序里,接口充当了父类,由接口指向了子类的实例对象,所以作为一个规则,就可以让其他子类实现功能,而传入接口引用,这样就实现了程序功能的拓展性。

 

可以说,我们通过主体去引用接口程序,就是在对外制定一个规则,同时主体使用这个接口(通常做法就是使用接口的引用),然后建立我们需要的类来实现接口的规则(复写接口的方法),然后对接(传入实现类的对象,因为接口引用指向子类对象,这就是多态),这样就完成规则的定制和外部功能的接入。之后只要我们符合这个规则,那么就可以实现好多不同的功能,进而实现了程序的拓展性。

0 0
原创粉丝点击