在讲解接口之前,抽象类是绕不过去的一个概念,接口可以认为是一个比抽象类还要抽象的类。
什么是抽象类?「包含一个或多个抽象方法的类就是抽象类,抽象方法即没有方法体的方法」,抽象方法和抽象类都必须声明为 abstract。例如:
// 抽象类
public abstract class Person {
// 抽象方法
public abstract String getDescription();
}
切记!「除了抽象方法之外,抽象类还可以包含具体数据和具体方法」。例如, 抽象类 Person 还保存着姓名和一个返回姓名的具体方法:
public abstract class Person{
private String name;
public Person(String name){
this.name = name ;
}
public abstract String getDescription();
public String getName(){
return name;
}
}
❝ 许多程序员都会「错误」的认为,在抽象类中不能包含具体方法。其实这也是接口和抽象类的不同之处,接口中是不能包含具体方法的。 ❞
「抽象类不能被实例化」。也就是说,如果将一个类声明为 abstract, 就不能创建这个类的对象。
new Person("Jack"); // Error
可以定义一个抽象类的对象变量, 但是它只能引用非抽象子类的对象。假设 Student 类是 Person 的非抽象子类:
Person p = new Student("Jack"); // Right
所谓非抽象子类就是说,如果创建一个继承抽象类的子类并为之创建对象,那么就「必须为父类的所有抽象方法提供方法定义」。如果不这么做(可以选择不做),子类仍然是一个抽象类,编译器会强制我们为新类加上 abstract 关键字。
下面定义扩展抽象类 Person 的具体子类 Student:
public class Student extends Person {
private String major;
public Student(String name, String major) {
super(name);
this.major = major;
}
@Override
public String getDescription(){ // 实现父类抽象方法
return "a student majoring in " + major;
}
}
在 Student 类中实现了父类中的抽象方法 getDescription 。因此,「在 Student类中的全部方法都是非抽象的, 这个类不再是抽象类」。
调用如下:
Person p = new Student("Jack","Computer Science");
p.getDescription();
由于不能构造抽象类 Person的对象, 所以变量 p 永远不会引用 Person 对象, 而是引用诸如 Student这样的具体子类对象, 而这些对象中都重写了 getDescription方法。