Java基础day08笔记:多态|多态中成员的特点|多态的应用示例|Object类

    01-面向对象(多态-概念)

        接下来说一下面向对象的第三个特征:多态

        何为多态呢?

        其实就是某些事物具有的多种表现形态。

        比如说,人分为男人和女人,就是人的两种表现形态。

        动物包括猫、狗.etc

        猫 x=new 猫();

        动物 x=new 猫();

        这两种定可以方法都可以哦。

        猫既具有猫的特征,也有动物的特征。

        来了一只猫,我们可以说这只猫猫好可爱,也可以说这个小动物好可爱。

        但是有个前提,猫得是动物的一种。

        以往呢,我们是某一种类型对应这种类型的实例,我们可以理解:猫 x=new 猫();

        而现在呢,类与类产生关系之后,我们发现,原来实体可以具备其他类型,这说明这个事物有多种存在形态。

        那么多态呢,我们强调的是在Java上对象中的体现。其实不在对象中也可以体现,比如说函数。重载和覆盖,就是函数多态性的体现。

        接下来围绕4点来完成多态的学习:

        1,多态的体现

        2,多态的前提

        3,多态的好处

        4,多态的应用

    02-面向对象(多态-扩展性)

        通过代码来展示。

        定义动物类。

        猫猫类继承动物类。

        狗狗类也继承动物类。

        让它们吃东西:

        都顺利吃上啦:

        但是我们想要这只猫去吃东西,得调用一次eat()方法,让那只猫去吃东西,又得调用一次eat()方法,这样是不是很麻烦呀!这句话在重复使用。

        这个时候是不是阔以封装方法~

        想让谁吃就调用这个方法就好啦。

        提高了代码的复用性。

        猫猫可以吃了,那狗狗呢,还是在重复吃。

        再写一个狗狗吃东西的function()方法吗?

        一年以后再养了一群猪猪呢?

        再写一个猪猪吃东西的function()吗?

        现在就有三个function()啦!

        可是还有很多其他动物,我们都要挨个写吗?那累死了!

        重新思考一下,不管是猫猫,狗狗,还是猪猪,它们都具备吃的行为。为什么它们都具备吃的行为呢?因为它们都是动物呀!

        那能不能把代码写成这样呢?

        这样c既是猫猫,又是动物,它吃的东西还是小鱼~

        这就叫多态在程序中的表现。

        1,多态的体现

                父类的引用指向了自己的子类对象。

                父类的引用也可以接收自己的子类对象。

        Cat c=new Cat();

        是本类类型指向本类对象。

        Animal c=new Cat();

        是父类类型指向本类对象。

        接下来重新写一下function()函数:

        这下好啦,猫猫、狗狗、猪猪都顺利吃到东西啦!

        这样就提高了代码的扩展性,后期再有其他小动物想吃东西就可以直接用。

        2,多态的前提

                必须是类与类之间有关系,要么继承,要么实现。

                通常还有一个前提:存在覆盖。(如果没有覆盖的话,也没有扩展它的意义了)

        3,多态的好处

                多态的出现大大的提高了程序的扩展性。

        4,多态的弊端

                提高了扩展性,但是只能使用父类的引用访问父类中的成员。

                不能预先去使用子类,那个时候子类还不在呢。都没有子类,你怎么去访问它呢?所以它有一个局限性。(有点不太明白)

                但是我们侧重扩展性。父类让你做什么去做什么就好啦。

    03-面向对象(多态-转型)

        Animal a=new Cat();

        这句话其实是做了类型提升,把猫猫提升成了动物。就像之前讲的byte b=2;int a=b;b就被提升成了int。它也叫做向上转型。        

        如果想要调用猫的特有方法时,如何操作?

        能向上转型,也能向下转型。

        强制将父类的引用,转成子类类型。

        但是这种情况下不可以强制转型哦:

        因为动物可能是猫猫,可能是狗狗,可能是猪猪。如果你说,给我一只小动物,那给你一只猫猫、狗狗、猪猪都可以;如果你说,给我一只小猫猫,那给你一只小动物,也就是说,可能给你猫猫,也可能给你狗狗,也可能给你猪猪,这就不对了。

        所以千万不要出现这样的操作:将父类对象转成子类类型。

        我们能转换的是父类指向了自己的子类对象时,该引用可以被提升,也可以被强制转换。

        多态自始至终都是子类对象在做着变化。(猫猫一会变成动物,一会变成猫猫)

        再来个例子。

        我是小楠,我有一只小猪猪叫小锴,我和小锴都足智多谋、鬼灵精怪、会讲课,所以小楠类和猪猪小锴类里面都有teaching()功能。小锴开了一个猪猪学习班,有一天,猪猪们来到我家找小猪猪小锴上课,可是小锴不在家,我就化装成小锴给猪猪们上课。这个时候我就发生了类型提升,提升成了小猪猪小锴。

        小猪猪小锴 x=new 小楠();

        x.teaching();

        我开始讲课了,脱口而出的是喵喵星语言。我不懂猪猪语言,所以把猪猪语言复写掉了,变成了喵喵语言。(所以运行出来的结果是子类的结果)

        课程顺利的讲完了,猪猪们都很喜欢我讲的课,(*^__^*) 嘻嘻~

        猪猪们都走了,这时候我的小伙伴来找我逛街,可是我现在化装成小猪猪小锴了,虽然小楠类里面有shopping()功能,可是小猪猪小锴类没有这个功能呀,而且她们都以为我是小猪猪小锴,我只好说,不好意思,我不会逛街。

        所以,x.shoping();失败啦!报错啦!

        她们都走了,我很伤心,就赶紧跑回卧室换装,我要变回小楠!我脱下了猪猪服,换上了漂酿的小裙裙,又变成了可爱的小楠٩(๑òωó๑)۶

        小楠 y=(小楠)x;

        换好衣服之后,我赶紧给小伙伴打电话说,我回来了,走!逛街去!

        y.shopping();

        我们愉快的去逛街咯。

        在这个过程中,自始至终是小楠在变化,一会变成小猪猪小锴,一会变成自己。

        多态中自始至终是子类在发生变化。

        那可以强制将小猪猪小锴变成小楠吗?不可以!为什么不可以?emmm...我好像举错例子了。

        重来一遍!

        故事开始了:

        从前,小猪猪小锴是一只可爱的猪猪宝宝。

        小猪猪小锴

        {

                void damajiang()

                {

                        System.out.println("哈哈哈哈~呜呜~呜呜~哈哈哈~呜呜呜~");

                }

                void hejiu()

                {

                        System.out.println("哈哈哈~哈哈哈~呼呼~呼呼呼~");

                }

                void shuilanjiao()

                {

                        System.out.println("呼呼~呼呼~哼哼哼~呼呼呼~呼呼呼~");

                        shuomenghua();

                        System.out.println("嘤嘤嘤~呼呼~呼呼呼~");

                }

                void shuomenghua()

                {

                        System.out.println("我不是小短腿!");

                }

        }

        后来,小猪猪小锴长大了,后来又结婚了,生了一窝可爱的小猪猪小小锴。小猪猪小锴喜欢打麻将,他的大鹅纸小猪猪小胖,继承了他的优良基因,也打得一手好麻将。

        小猪猪小胖

        {

                void damajiang()

                {

                        System.out.println("哈哈哈哈~哈哈哈~哈哈哈~哈哈哈哈哈~");

                }

                void hejiu()

                {

                        System.out.println("小口小口~吸溜吸溜~哈哈哈~");

                }

                void shuilanjiao()

                {

                        System.out.println("呼呼呼~");

                        shuomenghua();

                        System.out.println("流口水~呼呼呼~");

                }

                void shuomenghua()

                {

                        System.out.println("我麻麻好漂酿~");

                }

                void tingjiangzuo()

                {

                        System.out.println("我要学习!我要进步!");

                }


        }

        所以,小猪猪小锴类小猪猪小胖类里面都有damajiang()功能。

        有一天,小锴的朋友们打电话约他去打麻将,可是他不在家,电话被鬼灵精贵的小胖接到了。小胖心生一计,为什么不化装成爸比小锴替他去和朋友打麻将呢?于是就一口答应了下来。

        小猪猪小锴 x=new 小猪猪小胖();

        小胖精心打扮成了小锴的样子,去赴约啦。

        在麻将局上,他调用了自己的damajiang()功能,和小锴的朋友们打了一把又一把。

        x.damajiang();

        因为遗传了小锴的优良基因,又从小耳濡目染小锴的高超技艺,所以小胖青出于蓝而胜于蓝,它的damajiang()功能里有很多自己新创的麻将套路,这些是小锴都没有掌握的呢!因此,小胖在这个麻将局里赚得盆满钵满,小锴的朋友都连连称(吐)赞(槽)他今天手气好。

        打完了麻将,小胖心满意足的回家了。刚到家,还没来得及换掉化好的装,小胖的朋友们就来找他听讲座了。虽然小猪猪小胖类里面有tingjiangzuo()功能,可是小猪猪小锴类里面没有这个功能呀!小锴有打麻将功能,有喝酒功能,有睡懒觉功能,可是就是没有听讲座功能呀!

        这时,虽然小胖心里知道自己是小胖,知道自己和爸比不一样,是一个热爱学术的人,可是他外表是小锴的样子,所以,只好说,不好意思,我不会听讲座。

        所以,x.tingjiangzuo();失败啦!因为编译的时候检测到小猪猪小锴类里面没有tingjiangzuo()功能,所以编译报错啦!

        小胖的朋友们前脚刚走,小胖后脚就跑回房间里把妆卸了,变回了可爱的小胖。

        小猪猪小胖 y=(小猪猪小胖)x;

        然后打电话给小伙伴们,“等等我,听讲座走!”

        y.tingjiangzuo();

        于是,小胖和小伙伴们一起认真的听了讲座,在自己成为一名科学家的道路上又前进的一大步!

        在这个过程中,自始至终是小胖在变化,一会变成小锴,一会变成小胖自己。

        多态中自始至终是子类在发生变化。

        那可以强制将小锴变成小胖吗?不可以!为什么不可以?因为有小锴的时候有可能还没有小胖呢哈哈哈。就算这个时候小胖已经出生了,非要把小锴化装成小胖,那小锴有听讲座功能吗?木有!一去就露馅咯。

        在刚刚这个故事中,

        小猪猪小锴 x=new 小猪猪小胖();叫做向上转型。

        小猪猪小胖 y=(小猪猪小胖)x;叫做向下转型

        好,回来啦,从故事里出来,继续笔记。

    04-面向对象(多态-示例)

        5,多态的应用

        学生类:

        基础班学员类:

        高级班学员类:

        在主函数里调用:

        其实,我们可以把画红框的抽取出来,封装在一个函数中:

        再进一步,我们这个功能能不能把它抽取出来,单独封装成一个对象呢?然后由这个对象去操作学生。

        工具类:

        该怎么用它呢?

        我们把这件事情都交给DoStudent这个类去做就好啦,谁做传谁就OK。

        在这些类中,最基本的是Student类和DoStudent类,这两个类把功能都写完啦,后面的基础班学员和高级班学员都是后来才有的,后面也许还会有冲刺班,其他班,这些都可以再加,只要有这两个类作为基础,这个功能就都阔以实现。

        多态将对象调用这件事情变得简单了。以前是指挥某一类对象去做事情,现在是指挥某一批对象去做事情,因为找到了这些对象的共同所属类型。

    05-面向对象(多态中成员的特点)

        6,多态的出现代码中的特点(多态使用的注意事项)

        一个例子,父类和子类中的函数是这样的:

        这样调用会编译失败:

        因为在父类中找不到method3()方法。

        Fu f=new Zi();

        在编译的时候,对象还没有产生,这个时候会检查f所属于的类型当中,到底有木有method3()方法。如果有,就编译通过,如果没有,就编译失败啦。

        注释掉报错的语句,重新运行:  

        为什么是zi1、fu2呢?

        因为最终在执行的是对象。就像上次讲的例子,小胖化装成小锴帮小锴打麻将,但他用的麻将技巧是自己的,而不是小锴的。

        在多态中成员函数的特点:

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

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

        简单总结就是:成员函数在多态调用时,编译看左边,运行看右边

        面试中会考的一个例子:  

        这样运行结果会是什么呢?

        运行结果:

        为什么第一个打印的是fu的num呢?

        在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属的类)。

        Fu f=new Zi();

        这句执行之后,堆内存中产生两个num,父类引用f肯定会先找自己的num。

        再换一下,在Fu类和Zi类中都加一个静态的method4()方法(一般没有人去覆盖静态的):

        然后酱紫调用,这种题很要命的,开发不会出现这种情况,没人去覆盖静态的,那么它的运行结果是什么呢?

        发现打印结果是fu。

        刚刚说的成员函数在多态调用时,编译看左边,运行看右边,说的是非静态的。

        在多态中,静态成员函数的特点:无论编译和运行,都参考左边。

        调用method1()的时候为什么执行zi?因为method1()在方法区的非静态区。当我们在调用method1()的时候,f确实在指向这个对象,method1()运行的时候,最终是被对象运行。对象在调用这个方法的时候,它最后打印的或者访问的是对象中的这个数据。

        而静态方法,它本身不访问对象的特有数据,所以都可以直接用类名调用,这时只用看对象所属类中的成员。它访问的是静态区中的方法,不参考右边对象。

        当method4()方法一进内存,它就已经被绑定了,因为它是静态的方法,绑定在所属的类中。

        但是这种开发方式不多见。

        为什么说一般覆盖不用在静态上,用在静态上:

        这个时候运行的是zi的,如同被覆盖了一样。

        可是在多态上就不一样了。静态和非静态的绑定方式不一样,静态用的是静态绑定,非静态绑定是动态绑定。有区别。

        父类引用指向子类对象,对于静态方法调用的时候,父类走父类,子类走子类。

        现在把多态的各种情况都分析啦,后面这种情况不常见,可能只有面试会用到,所以说记住上面加粗体的结论就好啦。

        前面那种常见的要理解哦。

    06-面向对象(多态的主板示例)

        接下来举一个多态的小应用,把实际相结合一下~        

        需求很简单:

        这样写一下,这个程序就能用了,调用主板:

        但是这样写的话,这个程序就是一个死程序。

        这个程序在现实中就是这样的:一个板子,插个CPU,搞个内存条,插上硬盘,往机箱里面一封装,这个主板里就这么点东西。封装完,一开机,噔噔噔就开始运行了,就完事儿了。

        是不是缺什么呢?

        比如说,我运行了一段时间以后,我想上网了,可是我的主板没有上网这个功能,我想上网上不了。我想听音乐,也听不了。

        这时候怎么办呢?

        我们需要给主板提供一些扩展性功能,它不能像刚刚写的那样,毫无扩展性。

        改起来~

        写一个网卡类:

        在主板类里面加入使用网卡的功能:

        试着运行一下,靠谱哒:

        现在我想听音乐了,想加声卡。

        但是现在主板和网卡的耦合性非常强,它是焊在一起的,我们得把网卡弄下来,再把声卡焊上去,非常麻烦。

        而且后期还会有很多其他功能,也不知道后期都会有什么卡上来,为了降低这些卡与主板的耦合性,该怎么办呢?

        主板这个时候找了国际组织开会,说,卡卡们可以有它们自己的型号,也可以有它们自己的标准。我在主板上留一些槽,你做的卡卡前半段来供电,后半段来走数据,你做的卡卡想在我的主板上插,就按这个标准来。

        这时主板上面预留了很多插槽,给扩展留了余地。这时网卡和声卡和主板的依赖程度就没有那么大了。

        现在结合这个图,把代码重新写一遍:

        PCI接口:

        主板类:

        但是现在还没有对象,传null值会运行失败:

        所以在主板类中改一下这里,这下就可以运行了:

         网卡类:

        现在可以建立网卡对象通过PCI使用网卡啦:

        接口的出现降低了耦合性提高了功能的扩展性,多态的应用提高了程序的扩展性:

        这里的  PCI p=new NetCard();//接口型引用指向自己的子类对象。

    07-面向对象(多态的扩展示例)     

        接下来再讲一个应用。

        需求:        

        通过JDBC操作用户信息的类:

        使用它:

        这个时候发现一个问题,如果后面我们不想用JDBC连接数据库,想改用Hibernate连接数据库,是不是还得改呢?

        这个时候这个代码就得重新设计了。

        设计好了重新写代码,加入用户信息数据访问对象的接口:

        JDBC的类实现这个接口:

        在主程序中调用:

        Hibernate类也实现这个接口:

        也可以轻松调用啦:

        接口的出现,降低了耦合性,提高了扩展性。emmm...不是在讲多态么...

    08-面向对象(Object类-equals())

        接下来讲点特殊的东西。

        Object:是所有对象的直接或者间接父类,传说中的上帝。

        该类中定义的肯定是所有对象都具备的功能。

        这是Object类所具有的方法,也是所有继承Object类的类(即所有类)所具有的方法:

        接下来聊一聊里面的个别方法。

        Java认为,所有对象都具有比较性,都能比较俩对象是否相同。

        试一下使用这个比较的方法:

        我们发现,第一个equals接收的Demo类型,第二个接收的Person类型,而任何对象都具有比较性。再看看这个方法,对象是Object类的引用,所以不管什么对象,这个方法都能比。

        比较类中的数据:

        我们有必要写这个compare方法吗?父类已经提供了,为什么还要自己写。

        Object类中已经提供了对对象是否相同的比较方法。

        如果自定义类中的也有比较相同的功能,没有必要重新定义。

        只要沿袭父类中的功能,建立自己特有比较内容即可。这就是覆盖。

        覆盖好啦:

        但是这样调用就会报错:

        再改一下代码:

        OK啦。

        当然也有其他办法,比如说抛出异常,“你疯啦!怎么拿它们两个比呐!”

    09-面向对象(Object类toString())

        接下来讲这个方法:

        试一下:

        打印出来的结果,前面是这个对象所属的类,后面是这个对象的哈希值。

        所有对象都是依赖于类产生,所以用getClass:

        讲一讲Class,Class也是一个类:

        里面有个方法:

        我们打印一下类名和哈希值,和toString()的运行结果对比一下,证实了打印出来的确实是类名和哈希值:

        可以给中间再加两个@@,这样打印出来就一毛一样啦:

        看看toString的描述,确实是这样:

        但是这个哈希地址值感觉没啥意义,我们想让打印出来的东西有意义,在Demo类中复写一下:

        这样打印出来就变成这样了:

        通常我们经常都会进行复写操作,比如上面举的例子,建立对象特有的比较形式和字符串表现方式,父类默认的都没有什么意义。

        写类描述的时候,Object类中的方法都可能被复写,那为什么不把它里面的方法都抽象呢?因为这样Object类也变抽象了,那么随便定义一个类,就都被强迫去做这件事情,这样就会很麻烦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容