昨天学习了继承,一句话形容就是:
父亲可以有很多个儿子,但是儿子只能有一个亲爹。
今天学习了接口,一句话形容就是:
儿子只能有一个亲爹,但却可以有很多个干爹。
不得不说,这两句话简直生动形象地体现出了继承和接口的一些特点。
都说学计算机,写代码是一件挺枯燥乏味的事情,现在看来也挺有趣的嘛。
今天就让我们走进程序的世界,研究下什么叫接口?
一、接口的格式
还是以昨天的例子来理解接口:
动物园里有很多动物,分食草动物和食肉动物,食草动物又有小兔子等。
如何让这些动物进入动物园呢?
制定一个动物园接口。代码如下:
说明:
①定义了一个名叫动物园的接口:interface+接口名。
②接口的抽象方法:abstract+方法名。
③接口的默认方法:default+方法名。
④接口的静态方法:static+方法名。
将abstract,default,static这三个英文单词记下来,也就能很好地理解了。
所以综上:
一个接口,里面有抽象方法,默认方法、静态方法,现在随着JDK的更新,接口也有私有方法、私有静态方法。
但无论怎样,抽象方法是一个接口的核心。
下面就主要说下抽象方法
二、接口的抽象方法
动物园接口创建好了,有新的动物要进这个动物园怎么办?
要入园?实现我的接口就好了。
如何实现?这就要用到一个关键字implements,其中接口可以多实现,也就是一个类可以实现多个接口。
用现代的话理解就是:儿子只能有一个亲爹,但却可以有很多个干爹。
现在有一只小兔子想进入这间动物园,该怎么做?
①创建一个兔子类Rabbit,实现Zoo接口,格式:类名+implement+接口名。
②重写接口中的抽象方法。
抽象方法有一个特点,就是你必须得重写,不重写就没法实现接口。
什么意思呢?
就是一家动物园,要接纳新动物,就制定了一个规则:动物吃什么?
每个动物吃的都不同,就直接写了一个抽象方法eat(),只有方法名eat,没说具体要吃什么。
任何动物要入园,就得重写eat()这个抽象方法:
你得说明你吃什么(重写我的抽象方法),我才能让你入园(实现我的接口);
你不说明你吃什么(不重写我的抽象方法),我就不让你入园(没法实现我的接口)。
看到没,这叫啥?这就叫规则,所以我们常说写接口是在干啥,是在制定规则。
我制定了一个规则,具体啥内容我不写。任何实现类要实现我这个接口,就得写清楚。
写到这,我突然又想起了现实生活中的一个例子:
中学时语文作文,就一个题目或者一则材料,就得写一篇不少于800字的作文。
这写作文的过程不就相当于是实现接口的过程么?
太特么真实了……
三、接口的默认方法和静态方法
既然说接口是在制定规则,那抽象方法不就起到了制定规则的作用了么,还要默认方法和静态方法干嘛?
1.默认方法
一开始接口确实只有抽象方法,但是后来开发者发现,这个接口若是要拓展,增加一个抽象方法,所有的实现类都要重写方法,特繁琐。
什么意思呢?
动物园一开始制定的规则是:你想进动物园,必须说明你吃什么?
现在动物园想增加一个功能,就是想知道每个动物的名字叫什么?
如果把name()方法设定成抽象方法,那就是每个动物必须得告诉我你的名字,但问题是有的动物暂时还没名字,怎么办?
所以,如果不是强制性的要求,就可以制定成默认方法。什么时候有需求了重写就好,也可以一直不重写方法。
现在有一只兔子,没有名字,那就用接口的默认名(动物),突然有一天想给它取了一个新名字,叫小白,怎么办?重写默认方法就好了,重写以后它的名字就叫小白了。
说到这,我突然又想起来了现实里的一个例子:
我们登入很多网站,一开始都会有一个默认名,什么qq用户XXX,UC用户XXXX,这应该就是相当于接口里的默认方法吧?我们自己制定用户名,修改用户名,这个过程不就是在重写默认方法么?
2.静态方法
这个比较容易理解,static这个关键字前面就学习过,可以用类名.方法名直接调用。
在接口中,就是接口名.方法名直接可以调用。
接口有个特点,就是接口里的静态方法只能用接口名调用,其他都不行。
四、抽象类
在接口的抽象方法中,提到了一个概念,叫抽象类。
这个抽象类又是啥呢?
抽象类:有抽象方法的类就叫抽象类。如果一个类包含抽象方法,那么该类必须是抽象类。
它和接口很类似,也是子类必须要重写它的抽象方法,不然不行。
父类和子类的关系也就相当于接口和实现类的关系。
相同点;
都不能创建对象,也就是没法实例化,只能通过子类/实现类来创建对象。
子类/实现类必须重写抽象方法。
不同点:
不同的引用数据类型,一个是类(class),一个是接口(interface)
子类只能继承一个父类,但是子类可以实现多个接口;反过来就是一个抽象类只能有一个子类,但是接口能有多个实现类。
接口的设计具有更大的可扩展性,而抽象类的设计必须十分谨慎。
可拓展性是什么意思呢?
一个类只能继承一个父类,如果有一天想拓展一个新功能,那么只能改这个类,这个抽象类一改,它的所有子类都得改。
那么问题来了,我只有一部分子类需要这个新功能,其他的不要呀,用抽象类的话,不要都不行。
用接口的话,拓展一个新功能,重新再写一个新接口就好了,哪些类需要新功能,实现这个接口就好了,不用每一个类都得改。
总结: