面向对象的编程语言,拥有三大特性,分别是:“继承”,“多态”,“封装”。这三个特性贯穿了面向对象编程语言的方方面面,也是区别于面向过程语言的三个标志。所以,掌握这三个特性,将有助于你在学习面向对象编程方面取得更好的进步。或者你现在学的是java,以后你又想学其他的面向对象编程语言的时候,也能帮助你更快地“转型”。因为从上层建筑层面而言。所有的面向对象编程语言的思路都是差不多的,而这三大特性,则是思路中的支柱点。下面,我们就先重点讲解三大特性中的“继承”特性。
问题的引入:我们在前面几章学了面向对象编程中关于类与对象的相关知识。那么假设我们现在定义了一个动物类,具有吃饭和睡觉这么两个方法。那么它的代码形式是怎样的呢?请看:

class Animal{
    eat(){
    Sysotem.out.printf("我在吃草");
    }
    sleep(){
    System.out.printf("我在站着睡觉");
    }

那么我们接下来,直接实例化这个Animal对象,就可以得到一个吃草的并且是站着睡觉的动物了是吧,那么现在问题来了:

问题1.我想new出一个狮子,但是狮子是吃肉并且躺着睡觉的,怎么办?
问题2.我想new一个吃肉,躺着睡觉,并且还可以钻洞的动物,怎么办?

—————————–思考分割线—————————-

好了,思考完了,就该干活了。
第一个问题:要new一个狮子,还是吃肉和躺着睡觉的。但是我们没有狮子类啊,怎么办?简单,新建一个Lion类,定义一下就好啦:

class Lion{

    eat(){
    Sysotem.out.printf("我在吃肉");
    }
    sleep(){
    System.out.printf("我在躺着睡觉");
    }

第二个问题:要new一个吃肉,躺着睡觉,并且还可以钻洞的老鼠,怎么办?也简单,我们在new 一个老鼠类出来就好啦:


class Mouse{

    eat(){
    Sysotem.out.printf("我在吃肉");
    }
    sleep(){
    System.out.printf("我在躺着睡觉");
    }
    bore(){
    System.out.printf("我在愉快地钻洞");
    }

你看,问题是不是很简单的就被解决了?但是如果仔细思考一下的话,我们有没有发现,其实以上狮子类和老鼠类的代码,都有一部分地方和动物类是一样的?并且这才是两个需求,鬼知道以后的客户会不会还有可以上天入地,擒龙捉鳖的要求呢?那我们到时候是不是也要重新自定义相应的类呢?显然这是不可取的。多次重复地创建这些相似的类,不仅会使得你分不清谁和谁,还有可能让你的代码变得臃肿,难以维护。这就违背了我们当初设计面向对象编程语言的初衷。所以,我们也要对类进行下一步的优化。就是再抽象操作。我们知道,我们的类是经过对现实生活中的具象物质进行抽象得出的,那么,由于思考方向和需要的不同,我们创建出来的类可能也是不是很完善的。比如上面的老鼠类和狮子类。他们都是针对狮子和老鼠进行抽象得出的类。但是我们也知道,不管是狮子还是老鼠,他们都是动物,身上都有着动物的特征。那么我们能不能再把类进行抽象一下,抽取一些相同的特质,组成一个动物类呢?答案是可以的。这就是我们要讲到的继承的知识点。下面开讲了。
首先,什么叫继承呢?从理解上来说就是儿子获得了父亲所有的东西,并且这些东西是属于儿子的,儿子可以随意支配。那么从编程语言角度出发,就是一个类获取了另外一个类的全部方法,并且对这些方法进行自主的支配。在这里,被别人继承的类,我们叫父类,也叫超类或者基类。而继承了父类的类呢,就叫子类,也叫派生类。回到我们刚才的问题,我们可以把动物类作为一个父类,然后让狮子类和老鼠类作为子类去继承它,并且对里面的方法进行适当的修改。怎么实现呢?这里借助一个关键字extends,它的作用是声明父类。请看示例:

父类:Animal

Class Animal{
    eat(){
    Sysotem.out.printf("我在吃草");
    }
    sleep(){
    System.out.printf("我在站着睡觉");
}

子类1:Lion

Class Lion extends Animal{
     //修改相应的方法
    eat(){
    Sysotem.out.printf("我在吃肉");
    }
    sleep(){
    System.out.printf("我在躺着睡觉");
    }
}

子类2 :Mouse类

Class Mouse extends Animal{
     //修改相应的方法
    eat(){
    Sysotem.out.printf("我在吃肉");
    }
    sleep(){
    System.out.printf("我在躺着睡觉");
    }
    bore(){
    System.out.printf("我在愉快地钻洞");
    }
}

看到这里,或许你会说,这看起来好像没什么啊,该写的代码还是要写,这样我还不如重新写一个类呢!不急,让我们再来看下一需求:new一个吃草,站着睡觉,四条腿走路的长颈鹿,怎么弄呢?请看:
子类3. Giraffe类

Class Giraffe extends Animal{
    run(){
    Syetem.out.printfln("我四条腿走路");
    }
}   

有没有发现,我在这里只写了一个方法呢?这是因为父类中的eat方法和sleep方法都是和需求一致的,所以我们就直接拿来用而不用根据需求进行更改。也就是说: 当我们在继承一个父类的时候,可以根据实际需要对父类中的方法进行重写,从而获取实际所需要的实现步骤(如例子1和2)。同时,也可以在父类方法的基础上进行扩充(如例子2和3)。就好比说。儿子从父亲那里继承了所有的东西,那么父亲原来的房子是拿来住的,但是到了儿子这里,它不打算住,于是拿来出租。这就是方法的重写,而父亲原来就做房地产和银行的,到了儿子这里,觉得IT行业也很有前途啊,于是就又去做了IT行业,这就是类的扩充。但是要注意的是:子类必须实现父类所有的属性或方法什么意思呢?就是说:如果子类不对父类的方法进行重写,那么父类的方法也会在子类被加载的时候执行。而如果子类重写了方法之后,就只会加载重写后的方法。(例子3.没有重写方法,但实际上已经执行,不信?有图为证:)

父类:

子类继承至父类,并重写以及扩充相关方法:

测试,后面为结果:

至此,我们关于继承的介绍到此结束。注意的是我们在开发过程中是经常会用到继承的。所以掌握其特性对于一个开发者而言,是很必要的。最基础的需求,也是在开发的过程中知道需不需要继承,什么时候继承,为什么要继承,怎样去继承。也就是说,在开发的过程中,最后将这四个问题重复地问自己,这样的话可能会加深对继承的应用技巧哦。我们下一章的内容是:三大特性之-封装。敬请期待。

更多推荐

java-面向对象编程-三大特性之继承