教她写代码的那些日子 9 接口和抽象类

当一个女生愿意和你分享隐藏在心底的一些事情的时候,是不是就意味着,你在她心里已经有了一席之地了呢?我隐隐有这样的感觉,但我不敢那样去想,因为我的自卑,这是我一切痛苦的根源,但它深入骨髓,即便是刮骨疗伤也治不好的。所以,一方面我觉得她对我是有喜欢的,但另一个声音又大喊着:“没可能!”。这很是折磨人,我开始失眠起来,心情总是一时兴奋不已,一时又失落不已。终于我决定不要再这样折磨自己,我想要一个确定的答案。

“我送你一首诗吧。”我突然说。

她有些奇怪地看了我一眼,然后说:“好啊。”

于是我辗转反侧一个晚上的成果,就通过一页纸展现在她眼前:

我想

我是一块花生地

在寒风中发抖

萧索漫过了郁郁葱葱

我把一条死鱼

埋在花生地里

你是一场春雨

死鱼也长出了翅膀

你不要害怕

它只在夜晚绕着我飞

只把我吞没,像星辰

我始终没有勇气直白地表达我的想法,所以千言万语都融入到了这几行文字中了。当然那只是我自己那样觉得,所以当我满怀期待地看着她读完那些文字,却听到她淡淡地说看不懂时,我是极度失落的。

“戴老师,没想到你还会写诗呢。”她笑着说。

“没有,乱写而已。”我象征性谦虚地说,接着又问她:“你觉得这首诗写得怎么样?”

“虽然我不懂,但我还是觉得写得很好,我就写不出来。”

“那你有没有从这首诗中感受到一些东西?”我追问着。

“没有。”她很干脆地回答,然后又说:“你今天怎么这么奇怪呢?”

“奇怪吗?”

“不奇怪吗?突然说送我首诗,又问我感受的。”

听了她说出我奇怪的表现,我有些尴尬起来,于是干笑着说:“我就是突然间文思泉涌,就写出一首诗来,然后就希望有人夸夸呗,不然怎么体现我的文学气质啊。”

“这样啊,那要不要我再夸你几句?”

“好啊,你再夸几句。”

“嗯,文采飞扬、才思敏捷、妙笔生花,嗯...”她努力地想要再说出一些赞美的词汇来,可最终嗯了很久后还是放弃了,“哎呀,我这语文水平也不怎么样,就这几句了,你就将就着听听吧。”

“好吧,有你这几句赞美,就不枉我琢磨一晚上了,哈哈。”我笑起来,其实有没有答案,都不影响和她待在一起感到的快乐。

“一晚上不睡觉吗?那你厉害!”她说着竖了一下大拇指,然后又说,“我有个问题,一直没搞懂,在类定义里面,为什么那个main方法前面要加static这个关键字,而其他方法没有加呢?”

对于她突然的转移话题,我已经习以为常了,她对于学习java编程很是用心,也许正如她所说理性的思考能让人忘掉烦恼,也可能是她真的想从事程序员的工作,不管是什么原因,我想我都应该责无旁贷地教会她Java编程。于是,我也收拾起心情,开始了我的Java教学。

“因为加static关键字的是类方法,不加的是实例方法。”我解释到。

“那什么是类方法,什么是实例方法呢?”不出我所料,她一脸茫然的看着我问。

“哈哈。”我忍不住笑了起来,因为我觉得她茫然的样子真的很可爱。

“笑什么,你本来就几乎什么都没讲嘛。”

“是的,我只是觉得你的样子很好看。”

“本仙女的好看不用你说的,赶快给我讲这个static,好吗?”她佯装愠怒地说。

“类方法呢,就是类本身的方法,可以直接用它;实例方法呢,就是对象的方法,所以必须先有对象,然后通过对象来使用。就像......”我给出了一个很理论化的解释,同时,我也在思考一个比较通俗的例子,可一时却没想出来。

“就像之前我们写的Man类里面的show方法就是一个实例方法,所以在使用前必须先创建一个Man这个类的对象,然后再通过对象来使用这个show方法。”

说着,我翻出之前的代码给她看,她看了代码,思考了一下,然后点了点头,又说:“那我可以在Man这个类里面加一个类方法吗?”

“当然可以啊。”我说,“例如我们可以加一个展示世界上男人数量的一个方法。”

“我来写代码。”她说着就开始敲起代码来了。

她写的代码:

“怎么样?我写得不错吧?”看到程序运行后成功地输出了“世界上有30亿男人”这几个字,她得意地说。

“嗯,没错,看来你已经理解了什么是类方法,什么是实例方法。”

“差不多理解了吧。”

“那么有类变量吗?”我突然问到。

“这个......”她显然没有想到这点,一时也答不上来,但随即就笑起来,说:“你这么问,那肯定是有的了,哈哈。”

“那你知道怎么声明一个类变量吗?”

“一样用static这个关键字,对吗?”

“你很聪明,确实是这样的。那么在Man类中定义一个数量的类变量来存男人的数量呢。”

“这个简单。”她说着已经将代码写好了。

“很好,那你现在知道为啥那个main方法前面要加static这个关键字了吗?”

“我说说我的理解,你看看对不对啊。”她表现出谦虚的态度来,然后接着说,“因为mian方法是程序的入口,要给系统调用的,又因为系统调用的时候不会创建对象,所以要让系统调用得了就必须是一个类方法。”

“说得没错,确实是这样的。”我肯定了她的理解,然后又说,“看来你已经弄明白了类变量和类方法,那么总结一下呗。”

“好啊,那我就来总结一下。”于是,她变成了老师,我变成了学生:

1.类变量和类方法是属于类的,所以不需要实例化对象就可以使用。

2.类变量和类方法用关键字static来标识。

3.类变量和类方法一般用于表示不依赖于具体个体的属性,比如上面例子中的人数。

4.类变量的值不会因为创建了多个类的实例而改变。

“懂了没?”末了,她还不忘“关切”地问我这个学生是否学会了。

“懂了,哈哈。”我笑起来,她也笑着。

我们就这样笑了一会儿,突然觉得很傻,就很默契地都止了笑。

“那个,今天不会就学这个类变量和类方法吧?内容也太少了,你再多讲点。”她先开口说到。

“知道你好学,那我们就再来看看抽象类吧。”

“抽象类?是什么?”

“抽象类就是不能实例化的类。”

“为什么不能实例化呢?”

“因为它是抽象类。”

“额......,你这不是什么也没说吗?”

“哈哈,好了,不逗你了。”我说,“抽象类呢,一般来说它是对一类事物的抽象概括,它不能具体实例化一个实实在在的对象。就好比说动物,我们不能创建一个动物这样一个实实在在的事物出来,但是它是对老虎、狮子啊这些实实在在的动物的概括和抽象。”

说完,我停下来看向她,而她没有说话,显然在思考我对于抽象类的解释。

过了一会儿,她说:“可不可以这样理解,抽象类是这样一些类,它是为了描述一些类的共性而设计出来的类,它的主要作用就是方便对一些具有很多共性的类的概括描述。”

“可以这么说吧。”我说,“既然概念理解了,接下来我们就来看看,代码怎么写吧。”

“好啊。”她说着,就把笔记本电脑推到我的面前。

动物抽象类:

package com.lj.ac;

public abstract class Animal {
    protected int height;//身高
    protected int weight;//体重
    //抽象方法,移动
    public abstract void move();
    protected abstract String getName();
    //展示
    public void show(){
        System.out.println(getName()+":height->"+height+",weight->"+weight);
    }
}

狮子:

package com.lj.ac;

public class Lion extends Animal {
    private String name;
    public Lion(int height,int weight,String name) {
        this.height=height;
        this.weight=weight;
        this.name=name;
    }
    @Override
    public void move() {
        System.out.println("狮子只能在草原上奔跑!");
    }
    @Override
    protected String getName() {
        return "名为("+this.name+")的狮子";
    }
}

豹子:

package com.lj.ac;

public class Leopard extends Animal {
    private String name;
    public Leopard(int height,int weight,String name) {
        this.height=height;
        this.weight=weight;
        this.name=name;
    }
    @Override
    public void move() {
        System.out.println("豹子可以爬到树上去!");
    }
    @Override
    protected String getName() {
        return "名为("+this.name+")的豹子";
    }
}

草原上创建一只狮子和一只豹子并让它们动起来:

package com.lj.ac;

public class Steppe {
    public static void main(String[] args) {
        //创建一头狮子
        Lion lion=new Lion(20,10,"小狮");
        //这头狮子展示自己
        lion.show();
        //这头狮子动起来
        lion.move();

        //创建一头豹子
        Animal leopard=new Leopard(20,15,"小豹");
        //这头豹子展示自己
        leopard.show();
        //这头豹子动起来
        leopard.move();
    }
}

运行结果:

名为(小狮)的狮子:height->20,weight->10
狮子只能在草原上奔跑!
名为(小豹)的豹子:height->20,weight->15
豹子可以爬到树上去!

“怎么样?是不是很简单?”看到运行结果后,我问她。

“嗯,是没有几行代码,让我仔细看看。”她说着,夺过电脑,研究起我写的代码来。

我知道一会儿她一定有很多问题,所以我也没多讲什么。通过她发现问题,我来解答,这样一种方式,无疑是最快的学习方式。

过了一会儿,不出我所料,她开始发问了。

“抽象类都是用关键字abstract标注的,对吧?”

“对。”

“Animal类里面那个move方法,怎么没有方法体?”

“这叫抽象方法,它也由关键字abstract标注。抽象方法的作用在于定义一个方法,表明它的非抽象子类应该有的相关能力。抽象方法只能出现在抽象类里面,继承拥有抽象方法的抽象类的非抽象类必须实现父类所有抽象方法。这个也好理解,因为只能抽象类才能拥有抽象方法,所以子类通过继承拥有了抽象方法是不行的,就得覆盖抽象方法以使自己没有抽象方法。另一方面来说,抽象方法是抽象父类给出的一个非抽象子类的能力的定义,到具体的子类就应该去实现该能力。就像getName这个抽象方法,它表明所有动物都会有个名字,那具体这个名字是什么样的,就要具体到狮子的名字会加个狮子前缀,豹子的名字应该加豹子这个前缀。也就是说抽象类的抽象方法抽象概括了这一个大类事物都有的能力,但每个具体的类对于该能力的表现会是不一样的,就像这里的move方法,它说明动物都是能动的,但具体到狮子是怎么动,豹子是怎么动的是不一样的。”

我一口气说了很多,这显然让她一时无法完全接受,所以她摆了摆手,说:“你先停下,让我理一理。”

于是,我就很听话地不再说话,而她一边看代码,一边念叨着:“在抽象类里面可以用abstract声明抽象方法,抽象方法是没有方法体的,声明后的抽象方法可以被其他非抽象方法调用的,非抽象子类必须重写所有抽象父类的抽象方法。”

“嗯,差不多懂了。”最后,她点了点头,说。

“那你知道为什么要有抽象方法吗?或者说抽象方法的好处是什么?”我问。

“这个很明显啊,在这个例子中,不管是狮子还是豹子,它们都有一个共同的方法show,这个方法在不同动物中只是名字部分不同而已,那在父类Animal中写一个通用方法,子类去继承就避免了重复编码。至于名字的不同就通过getName这样一个抽象方法,先在父类中给出定义,再在不同子类中做不同实现,从而使show方法中关于名字的部分呈现不同的结果。”

“说得没错,因为可以用父类变量引用子类对象,所以我们可以写一个通用方法,通过传不同子类,来达到不同的效果。”

“就像这样。”看她有些迷惑的样子,我决定还是写个例子,她一看就明白了。

package com.lj.ac;

public class Steppe {
    public static void main(String[] args) {
        //创建一头狮子
        Lion lion=new Lion(20,10,"小狮");
        //创建一头豹子
        Animal leopard=new Leopard(20,15,"小豹");
        //狮子跑
        move(lion);
        //豹子爬树
        move(leopard);
    }
    public static void move(Animal animal){
        animal.move();
    }
}

运行结果:

狮子只能在草原上奔跑!
豹子可以爬到树上去!

“哦哦,明白了。”她看着运行结果说。

“嗯,这其实就是java中的面向对象的三大基本特征之一多态。”我接着说,“多态就是这样,同一个引用类型,使用不同的实例,执行不同的操作。”

“嗯,懂了。还有一个问题,抽象类里面可以没有抽象方法么?”

“当然可以啊。”我很肯定的回答。

“那没问题了,好开心,又学到很多知识。”她说着开心地笑起来。

看着她开心,我也很开心,但我准备给她出个难题,于是我说:“假如有这么一个东西,它即可以像动物一样移动,又可以像植物一样进行光合作用,要实现多态,应该怎么做?”

“那还不简单,写一个动物抽象类,里面定义一个移动的抽象方法;再写一个植物抽象类,在里面定义一个光合作用的抽象方法;最后在写这个你假如的东西的类,去继承动物和植物这两个抽象类,同时去实现移动和光合作用这两个方法。”她很得意地说。

“但是java中类只能单继承,也就是一个类只能有一个父类。”我无情的泼了一盆冷水。

“是吗?那怎么办呢?”她犯难地说。

“哈哈,这个时候就该今天要讲的另一个知识点接口出场了。”

“呵呵,我就知道你有办法,那么就别废话了,开讲吧。”她扑闪着一双大眼睛看着我说。

“嗯,我还是写个例子吧,也许你一看就懂了,也不用我讲什么。”我说。

“这么相信我的学习能力?”

“那当然了,你那么聪明伶俐的。”

移动接口:

package com.lj.interfaces;

public interface MoveInterface {
    void move();
}

光合作用接口:

package com.lj.interfaces;

public interface PhotosynthesisInterface {
    void photosynthesis();
}

像植物又像动物的东西:

package com.lj.interfaces;

public class BotanyAnimal implements MoveInterface,PhotosynthesisInterface{
    @Override
    public void move() {
        System.out.println("我像动物一样动起来了!");
    }

    @Override
    public void photosynthesis() {
        System.out.println("我像植物一样进行光合作用了!");
    }
}

另一个像植物又像动物的东西:

package com.lj.interfaces;

public class AnimalBotany implements MoveInterface,PhotosynthesisInterface{
    @Override
    public void move() {
        System.out.println("我以另一种方式,像动物一样动起来了!");
    }

    @Override
    public void photosynthesis() {
        System.out.println("我以另一种方式,像植物一样进行光合作用了!");
    }
}

应用程序:

package com.lj.interfaces;

public class Application {
    public static void main(String[] args) {
        BotanyAnimal botanyAnimal=new BotanyAnimal();
        move(botanyAnimal);
        photosynthesis(botanyAnimal);
        AnimalBotany animalBotany=new AnimalBotany();
        move(animalBotany);
        photosynthesis(animalBotany);
    }
    static void move(MoveInterface moveInterface){
        moveInterface.move();
    }
    static void photosynthesis(PhotosynthesisInterface photosynthesisInterface){
        photosynthesisInterface.photosynthesis();
    }
}

运行结果:

我像动物一样动起来了!
我像植物一样进行光合作用了!
我以另一种方式,像动物一样动起来了!
我以另一种方式,像植物一样进行光合作用了!

“果然很容易就懂了。”看完代码,她显出轻松的神态来。

“真的懂了吗?那你给我讲讲。”

“嗯,那我就来总结一下,你看我说得对不对。”

1、声明一个接口用关键字interface,而不是class。

2、接口中的方法虽然是抽象方法,却不用像抽象类那样用abstract标注。

3、一个类可以实现多个接口,实现接口用关键字implements ,后面跟上要实现的接口列表。

4、接口可以用来声明变量,但是需要引用到实现了该接口的类对象。

5、通过接口实现了多态。

“总结得不错。”我肯定了她的总结。

“那是。”得到我的肯定,她很是得意,笑着说。

“既然你完全懂了,那我问你几个问题吧。”

“你问吧。”

“在接口中可以写非抽象方法吗?”

“这个...,可以吗?”她显然没想到这个问题,于是她将回答变成了问问题。

“答案是不可以。”我只好回答了这个问题。

“在接口中可以定义变量吗?”我接着问。

“不可以。”她想都没想就回答到。

“嗯,算正确吧。”

“什么叫算正确呢?”

“因为在接口中确实不能定义变量,但是可以定义常量。在接口中常量的定义可以省略final关键字,以及public和static关键字,但是它相当于同时使用了这三个关键字。当省掉final和public关键字,它看起来像变量,就像这样。”说着,我在移动的那个接口上加上一个常量。

package com.lj.interfaces;

public interface MoveInterface {
    int speed=10;
    void move();
}

“嗯,懂了。那还有什么需要注意的吗?”

“好像没有了,恭喜你已经学会了java中的接口。”

“要谢谢戴老师教得好。”她故作客气地说,说完又忍不住笑起来。

美好的时光总是过得很快,我看了看时间,又是晚上9点多了。

“今天就学这么多吧,该回家了。”我说。

“是呀,该回家了,时间过得真快。”她说。

于是,我们收拾了一下,并肩走出公司大门。外面街道上已经灯火璀璨,我抬头看了看天,却没有看到星星,街面上的灯光将星光吞噬得一干二净。

ps:

这一节的几个关键点:类方法和类变量,抽象类,接口,多态

猜你喜欢

转载自blog.csdn.net/m0_46455711/article/details/112387051
今日推荐