首先我们需要知道"Abstract 抽象类"(abstract class)和"Interface 接口"(interface)是支持抽象类定义的两种机制.
1、Abstract 抽象类
那么在Java中什么是抽象类呢?
在Java中由于多态的存在,一个类可以作为父类被多个子类继承,例如:从Person父类派生的Student子类和Teacher子类都可以覆写run()方法。
class Person {
public void run() { … }
}
class Student extends Person {
@Override
public void run() { … }
}
class Teacher extends Person {
@Override
public void run() { … }
}
如果父类Person的run()方法没有需要执行的代码逻辑,能否去掉方法体中的执行语句?答案是不行,因为会导致编译错误,因为定义方法的时候,必须实现方法的语句。能不能去掉父类的run()方法?答案还是不行,因为去掉父类的run()方法,就失去了多态的特性。例如,之前定义runTwice()就无法编译!
所以,如果父类的方法本身不需要实现任何功能,仅仅是为了定义方法签名,目的是让子类去覆写它,那么,可以把父类的方法声明为抽象方法: 把一个方法声明为abstract,表示它是一个抽象方法,本身不能有方法体。因为这个抽象方法本身是无法执行的,所以,此时的Person类也被视为抽象类,抽象类无法被实例化。编译器会告诉我们,无法编译Person类,因为它包含抽象方法。
我们在代码中来看:
错误:
class Person { //此时编译器会报错
/*抽象方法 1、没有方法体
* 2、在修饰符和返回值之间加abstract关键字
* 3、必须存在于有abstract抽象类中
*/
public abstract void run();
}
正确:
abstract class Person {
/*抽象方法 1、没有方法体
* 2、在修饰符和返回值之间加abstract关键字
* 3、必须存在于有abstract抽象类中
*/
//抽象方法1
public abstract void run();
//抽象方法2
public abstract void say();
}
总结:
如果一个class中定义了某个方法,该方法没有具体执行代码(方法体)。那么,这个方法就是抽象方法,抽象方法使用abstract修饰。因为无法执行抽象方法,因此这个类也必须定义为抽象类(abstract class )。也可以理解为:抽象方法必须定义在abstract class 抽象类中。(注意:抽象类中不一定存在抽象方法)
2、Interface 接口
在抽象类中,抽象方法本质上是定义行为规范:规定父类中的抽象行为(抽象方法),要求所有子类必须对该抽象方法进行实现。从而,实现对子类行为规范的约束。主要用于实现多态。 但是,如果一个抽象类没有字段(成员变量),并且所有方法全部都是抽象方法,这时就可以把该抽象类定义为interface接口。在Java中,使用interface关键字声明一个接口:
interface Person {
void run();
String getName();
}
所谓interface接口,就是比抽象类还要更佳抽象的一种纯抽象的代码结构。因为它连字段(成员变量)都不能存在,只能包含常量、抽象方法、默认方法等。另外,接口定义的所有方法默认都是public abstract的,所以这两个修饰符不需要显示的定义出来(写或不写效果都一样)。
当一个具体的class去实现一个interface时,需要使用implements关键字。要求所有子类必须对该抽象方法进行实现,举个例子:
class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(this.name + " run");
}
@Override
public String getName() {
return this.name;
}
}
在Java中,一个类只能extends继承自另一个类(单继承)。但是,一个类可以implements实现多个interface接口(多重实现)。例如:
// 实现了两个interface
class Student implements Person, Hello {
...
}
此外,接口可以定义default方法(JDK版本 >= 1.8),default方法可以包含方法体。default方法和抽象类的普通方法是有所不同的。因为interface没有字段,default方法无法访问字段,而抽象类的普通方法可以访问实例字段。
实现类可以不必覆写default方法。default方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。例如,把Person接口的run()方法改为default方法:
public class Main {
public static void main(String[] args) {
Person p = new Student("Xiao Ming");
p.run();
}
}
interface Person {
String getName();
default void run() {
System.out.println(getName() + " run");
}
}
class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}