一、前言
面向对象(OPP)的编程,如果要提高程序的复用率,增加程序的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程。由于抽象类和接口之间在对于抽象类定义的支持方面具有很大的相似性,一开始接触到这两个概念时,还是有一些混淆的。但其实两者之间还是有很大的区别的,对于它们的选择甚至可以反映出对于问题本质的理解、对设计意图的理解是否正确合理。因此,在看了很多相关的文献资料之后,决定亲自写一篇详细一点的关于抽象类和接口的文章,通过梳理和整合,让逻辑和思路更加清晰。二、抽象方法和抽象类
2.1 抽象方法(Abstract method)
-
基本概念:抽象方法其实就是在抽象出这个问题有解决方法,但是并不能实际的告诉你该怎么做,所以就需要把每一个抽象方法都实例化,告诉程序每一步该怎么做,这样才能完成目标。
🌰举个例子,比如说我有个抽象方法是吹小号,但是我并不知道五线谱,而且我也不知道指法,所以我得找到一个实例化的方法,告诉我每一步该怎么做,手应该放哪里,嘴该用多大的力气,这个就是抽象方法吹小号的实例化。 -
一般格式:访问修饰符 + abtract 关键字+ 返回类型 + 方法名 + 参数列表
public abstract void getArea();
- 抽象方法的规定
a.只有方法头,没有方法体。
b.在基类中出现,在派生类中被重写。
c.构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
2.2 抽象类(Abstract class)
抽象类就相当于一个现实的模板
- 基本概念(有>=1个抽象方法的类)
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。 - 一般格式:访问修饰符 + abtract 关键字+ 返回类型 + 方法名 + 参数列表
public abstract class Geometry {
public abstract void get Area(); // 在抽象类中声明
}
// 在派生类中重写
@Override
public double getArea() {
}
- 抽象类的规定(避免踩坑!!):
a.抽象类不能被实例化(很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
b.抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
c.抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
d. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
2.3 代码实例
public class Animal{
public void bark(){}
}
public class Cat extends Animal{
public void bark(){
System.out.println("喵喵喵");
}
}
public class Dog extends Animal{
public void bark(){
System.out.println("汪汪汪");
}
}
❗解释说明:
可以看到,父类Animal有一个叫唤的方法bark(),两个子类都继承了这个方法,并进行了重写,Cat是喵喵叫,Dog是汪汪叫。因此知道Animal到底怎么叫?它的bark()方法体里应该输出什么样的叫声,就能比较好地理解抽象方法和抽象类的含义和用法。
显然,动物是个抽象的集合名词,我们并不知道动物Animal怎么叫,所以,bark()方法在父类中实现不了,或者说实现了没有任何意义,bark()方法只能在子类中根据具体情况去实现。这样的话就可以把父类Animal中的bark()方法声明为abstract抽象方法,此时这个类也成了abstract抽象类。
所以可以看出抽象类自己并不能实例化,它存在的意义就是为了让子类继承。对于一个父类,它的某个方法在父类中实现没有任何意义,必需在子类中根据具体情况实现,那么这个方法可以声明为abstract抽象方法,此时这个父类也成了abstract抽象类。
三、接口(Interface)
- 基本概念
知道了抽象方法和抽象类,接下来就需要了解一个另一个和它相关的概念——接口。接口不是类,接口被看作是一种特殊的类。一个类通过继承接口的方式,从而来继承接口的抽象方法。接口跟抽象类很相似,不能只定义一个方法,而实现接口的类不去重写接口的方法,除非实现接口的类是抽象类,否则该类要重写定义接口中的所有方法。一个类可以实现多个接口,但是只能继承一个父类。接口使用关键字interface来声明。
- 一般格式 :
public interface 接口名字
{
(方法头……)
}
- 接口的特性
1、接口中每一个方法也是隐式抽象的,接口中的方法也会被隐式的指定为public abstract。
2、接口中可以含有变量,但是接口中的变量会被隐式的指定为public static final 变量。
3、接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
4、当类实现接口的时候,类要实现接口中所有的方法,否则类必须声明为抽象类。 - 抽象类和接口的区别(主要)
1、抽象类中的方法可以有方法体,但是接口中的方法没有方法体。
2、抽象类的成员变量可以是各种类型的,而接口中的变量只能是public static final类型的。
3、接口中不能含有静态代码块以及静态方法,而抽象类是可以有静态代码块和静态方法的。(JDK 1.8 之后,接口里可以有静态方法和方法体了)
4、一个类只能继承一个抽象类,而一个类却可以实现多个接口。
补充:
- 代码实例
(1)接口的实现
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
运行结果:
Mammal eats
Mammal travels
(2)接口的继承
// 文件名: Sports.java
public interface Sports
{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
// 文件名: Football.java
public interface Football extends Sports
{
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
// 文件名: Hockey.java
public interface Hockey extends Sports
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
解释说明:Hockey接口自己声明了四个方法,从Sports接口继承了两个方法,这样,实现Hockey接口的类需要实现六个方法。相似的,实现Football接口的类需要实现五个方法,其中两个来自于Sports接口。
(3)接口的多继承
public interface Hockey extends Sports, Event
解释说明:以上的程序片段是合法定义的子接口,与类不同的是,接口允许多继承,而 Sports及 Event 可能定义或是继承相同的方法。
(4)标记接口
package java.util;
public interface EventListener
{}
解释说明:简单形象的说就是给某个对象打个标(盖个戳)标记接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。
四、心得感悟
总的来说,抽象类(之所以有抽象这两个字,是因为抽象类里边的方法是没有方法体的,只有方法的声明)就是一种特殊的类,这种类不能被实例化,就是说你不能通过这个类new一个新的对象,它只能由其派生类(子类)去重写。而接口就是更加特殊的抽象类。
五、参考资料
1.https://blog.csdn.net/chajinglong/article/details/78855420
2.https://www.runoob.com/java/java-tutorial.html