前言
这个问题其实UP在大学期间上关于JAVA的课的时候就曾经遇到过,但是当时自己当时还是太菜了,对计算机也没什么兴趣,只是应付性的在网上查查答案,然后死记硬背,最后熬过考试.想想当初那门课程还拿了一个A,哈哈哈哈.
不扯皮了,主要是这几天UP自己重新复习JAVA基础的时候,又重新看到这个概念了,只怪当初自己没怎么了解,所以根本就没什么印象,看到之后还是根本分不清这两者到底有啥区别.所以就重新查阅了资料并且加上自己的理解.希望能够对你有帮助.
如果你觉得文章写得还可以或者文章对你有帮助的话,还请给UP赏个一键三连.UP在这里谢谢各位了.
并且由于UP自己最近在复习java基础所以会不定期的发一些自己关于基础的理解的文章,其实也有点类似于面经的的意思了啊.所以小伙伴们如果不想错过后续的文章的话,可以点击上方蓝字,关注UP.
抽象类与接口的概念
我们先介绍一下什么是抽象类什么是接口.
抽象类:
我们看到抽象类这个词语的时候,可能本能的反应就是先想到抽象的反义词具体.其实在现实生活中存在着很多具体与抽象的例子.就比如狗,狗是一个很抽象的概念,因为存在着很多具体的种类,像拉布拉多,金毛,边牧,哈士奇等等,所以我们为了统一这种概念于是就将这些具体的种类全部都抽象成了一个概念即狗.就如下图所示:
抽象类其实和我们上面的例子想要表达的内容是一样的.因为我们在开发的过程一定会遇到很多这样的情况,很多的类在本质上都是存在着一定的共性的,所以一般会把这部分的共性抽取出来作为抽象类.然后其他的具体类只需要继承该抽象类就可以在直接实现抽象类中的方法.不需要再重复性的创建函数并实现了.就比方我们下图所示:
到这里我们就基本上了解抽象类的基本概念了.接下来我们来了解一下什么是接口.
接口:
其实大家在平常的开发过程中可能最经常碰到的就是接口.这个接口可能是我们自己写的接口,又或者是第三方的接口.其实本质上都是调用已经写好的方法或者是函数,从而方便我们的开发.
所以接口其实泛指的就是供给我们调用的函数或者是方法.如果用更加直白的话来说的话:接口就是一个包含多个函数的集合.
我们上面说了接口一般都是提供给别人调用的,所以接口基本上就是用来帮助别人扩展自己的系统或程序的.举一个我们生活中的例子:
一般我们的灯只有开关的功能,但是呢我们现在有一个需求,就是看看能不能顺便让我们的灯监测我们的温度,如果出现温度异常的时候,就让我们的灯开始发出警告信息.这时候我们的一般做法就是在我们的灯里面集成我们的光感传感器以及报警传感器,这样我们的灯就能够实现检测温度并且异常情况下报警的功能了.如下图所示:
在这个例子里面,我们的接口就类似于上图中的两个传感器,正是因为加入了这两个传感器,我们才能够对我们一般的灯扩展监测,报警的功能.
看完现实生活中的例子之后,我们再把这个例子类比到我们的程序中应该就是下面这样的.我们定义一个类叫做Light(灯):
public class Light { public void on() { System.out.println("开灯"); } public void off() { System.out.println("关灯"); } }
之后我们再定义一个叫做MonitoringAlarm(监测报警)
的接口:
public interface MonitoringAlarm { void monitor(); void alarm(); }
之后我们就需要让我们的Light去实现MonitoringAlarm接口中的方法即可:
public class Light implements MonitoringAlarm{ public void on() { System.out.println("开灯"); } public void off() { System.out.println("关灯"); } @Override public void monitor() { // TODO Auto-generated method stub System.out.println("监测温度"); } @Override public void alarm() { // TODO Auto-generated method stub System.out.println("报警"); } }
这样我们就完成了对于灯的功能的扩展.
理解了上面例子之后,大家对于接口的基本概念就了解的差不多了.接下来我们就分析一下抽象类以及接口这两者的特点.
抽象类与接口的特点
抽象类的特点:
在程序中我们一般都是通过abstract这个关键字来表示抽象的概念,如果某个方法或者某个类的前面加上了abstract这个关键字,那么就代表这是一个抽象的方法或者是抽象的类.这就是我们的抽象类与一般的类的第一个区别,就比方下面我举的这两个例子:
//抽象类 public abstract class animal{} //正常的类 public class animal{} //抽象方法 public abstract void sleep();
大部分的文章都会强调一点那就是抽象类中一定会有抽象方法,其实这个观点是不对的,只要这个类前面添加的abstract关键字,那么这个类就是抽象类.只不过一般情况下抽象类中一般都会有几个抽象方法.就比方我们下面的两张图所演示的一样:
有抽象方法的抽象类:
没有抽象方法的抽象类:
所以不管有没有抽象方法,只要类的前面加上了abstract这个关键字,那么这个类就是抽象类.
但是相反的,如果一个类里面有抽象方法那么这个类必定是抽象类.否则是会直接报错的,就比方我下面两张图所演示的一样:
所以理清楚上面的逻辑之后,我们差不多也能够得到下面的推理顺序:
最后在给大家看几个例子:
//抽象类1=>没有抽象方法的抽象类 public abstract class animal{} //抽象类2=>有抽象方法的抽象类 public abstract class animal{ public abstract void sleep(); } //不是抽象类 public class animal{}
其次就是抽象类中的抽象方法都是没有函数体的,如果添加了函数体的话就会报错,就如下图所示:
所以抽象方法都是只包含函数的名称,不包含函数具体的执行方式.就比方下面的几个例子:
public abstract class animal{ //抽象方法没有函数体,没有函数的具体功能 public abstract void sleep(); //一般的有函数体的方法,函数里面有具体的功能 public void eat(){ System.out.println("俺要干饭"); } }
上面我们说过了抽象类的本质还是一个类,那么java中我们常说的的对象实例化的概念,抽象类是否又可以呢?
这就是抽象类和我们一般的类的另外一个区别了.我们知道在java中万物即对象,所以一般的类都是可以直接通过new关键字进行实例化的,但是抽象类就不行,抽象类本身是不能实例化的,所以下图所示的这种创建方式是不允许的:
抽象类只能是在被别的类继承了之后,才能通过继承该抽象类的类来进行实例化.就如我下面两张图所示:
可以看到虽然能够创建一个抽象类的对象,但是这个实例化的过程本质上还是实例化的继承了抽象类的类,并非是直接实例化的我们的抽象类.
并且我们可以看到继承了抽象类的类是必须实现抽象类的抽象方法的,否则还是会报错的,如我下面两张图所示:
并且每个类只能继承并实现一个抽象类,不能继承多个抽象类,否则就会报错,如下图:
我们可以看到每个类只能继承并实现一个抽象类.
最后我们总结一下抽象类的特点有哪些:
必须通过abstract关键字修饰
抽象类中不一定有抽象方法,可以有也可以没有.
抽象类既可以有抽象方法,也可以有一般方法
抽象类的抽象方法不能包含方法体
抽象类不能实例化,只能通过继承了抽象类的类来进行实例化
继承了抽象类的类必须要实现抽象类中的抽象方法,并且只能继承一个抽象类