你好!在过去的课程中,我们遇到了接口并弄清楚了它们的用途。今天的话题与之前的话题相呼应。让我们谈谈Java中的抽象类。
正是由于这种“混乱”,对象不知道该表现出什么行为,Java 的创建者才放弃了多重继承。但是,您会记得 Java 类可以实现多个接口。 顺便说一句,在您的学习中,您已经至少遇到过一个抽象类!

为什么类被称为“抽象”
您可能还记得“抽象”是什么——我们已经讲过了。:) 如果您忘记了,请不要害怕。请记住:OOP 的一个原则是,在设计类和创建对象时,我们应该只识别实体的主要属性并丢弃次要属性。例如,如果我们正在设计一个SchoolTeacher
类,我们几乎不需要“高度”属性。实际上,此属性与教师无关。但是如果我们要创建一个BasketballPlayer
类,那么增长将是一个重要的特征。所以听着。一个抽象类就像它们来的一样抽象——对于一组未来的课程来说,这是一个未完成的“空白”。空白不能按原样使用。太“生”了。但它描述了继承抽象类的未来类将拥有的某些状态和一般行为。
抽象 Java 类的示例
考虑一个简单的汽车示例:
public abstract class Car {
private String model;
private String color;
private int maxSpeed;
public abstract void gas();
public abstract void brake();
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
}
这就是最简单的抽象类的样子。如您所见,它没什么特别的:) 为什么我们需要它?首先,它以最抽象的方式描述了我们所需的实体,即汽车。我们使用抽象这个词是有原因的。在现实世界中,没有“抽象汽车”。有卡车、赛车、轿车、轿跑车和 SUV。 我们的抽象类只是一个“蓝图”,我们稍后将使用它来创建汽车类。
public class Sedan extends Car {
@Override
public void gas() {
System.out.println("The sedan is accelerating!");
}
@Override
public void brake() {
System.out.println("The sedan is slowing down!");
}
}
这与我们在继承的课程中谈到的非常相似。但是在那些课程中,我们有一个 Car 类,它的方法不是抽象的。但该解决方案有许多缺点,这些缺点已在抽象类中得到修复。首先,您不能创建抽象类的实例:
public class Main {
public static void main(String[] args) {
Car car = new Car(); // Error! The Car class is abstract!
}
}
Java 的创建者专门设计了这个“功能”。再次提醒:抽象类只是未来“普通”类的蓝图。你不需要蓝图的副本,对吧?而且您不会创建抽象类的实例 :) 但是如果类Car
不是抽象的,我们可以轻松地创建它的实例:
public class Car {
private String model;
private String color;
private int maxSpeed;
public void gas() {
// Some logic
}
public void brake() {
// Some logic
}
}
public class Main {
public static void main(String[] args) {
Car car = new Car(); // Everything is fine. A car is created.
}
}
现在我们的程序有某种难以理解的汽车——它不是卡车,不是赛车,也不是轿车,而且完全不清楚它是什么。这是自然界中不存在的非常“抽象的汽车”。我们可以使用动物提供相同的示例。想象一下如果Animal
类(抽象动物)。目前还不清楚它是什么动物,属于什么科,有什么特征。在您的程序中看到这一点会很奇怪。自然界中没有“抽象动物”。只有狗、猫、狐狸、鼹鼠等。抽象类将我们从抽象对象中解放出来。它们为我们提供了基本的状态和行为。例如,所有汽车都应该有model、color和maximum speed,你应该能够应用油门和刹车。就是这样。这是一个通用的抽象计划。接下来你设计你需要的类。 注意:抽象类中的两个方法也被指定为abstract,它们没有任何实现。原因是一样的:抽象类不会为抽象汽车创建默认行为。它们只是表明每辆车应该能够做什么。但是,如果确实需要默认行为,则可以在抽象类中实现方法。Java 不禁止这样做:
public abstract class Car {
private String model;
private String color;
private int maxSpeed;
public void gas() {
System.out.println("Gas!");
}
public abstract void brake();
// Getters and setters
}
public class Sedan extends Car {
@Override
public void brake() {
System.out.println("The sedan is slowing down!");
}
}
public class Main {
public static void main(String[] args) {
Sedan sedan = new Sedan();
sedan.gas();
}
}
控制台输出: “Gas!” 如您所见,我们在抽象类中实现了第一个方法,而不是第二个方法。因此,我们Sedan
类的行为分为两部分:如果调用该gas()
方法,则调用'上升'到Car
抽象父类,但是我们覆盖了类brake()
中的方法Sedan
。这样非常方便和灵活。但是现在我们的类不那么抽象了?毕竟它的方法实现了一半。这个实际上是一个非常重要的特性——如果至少有一个方法是抽象的,那么这个类就是抽象的. 两种方法中的一种,或至少一千种方法中的一种——都没有区别。我们甚至可以实现所有的方法,并且不保留任何抽象方法。那么它就是一个没有抽象方法的抽象类。原则上,这是可能的,编译器不会产生错误,但最好避免它:抽象这个词失去了意义,你的程序员同行们会很惊讶:/ 同时,如果一个方法被标记使用抽象一词,每个子类都必须实现它或将其声明为抽象。否则,编译器将产生错误。 当然,每个类只能继承一个抽象类,所以抽象类和普通类在继承上没有区别。不管我们继承抽象类还是普通类,都只能有一个父类。
为什么Java没有类的多重继承
我们已经说过 Java 没有多重继承,但我们还没有真正探究为什么。让我们现在尝试这样做。事实上,如果 Java 具有多重继承,子类将无法决定它们应该选择哪种特定行为。假设我们有两个类——Toaster
和NuclearBomb
:
public class Toaster {
public void on() {
System.out.println("The toaster is on. Toast is being prepared!");
}
public void off() {
System.out.println("The toaster is off!");
}
}
public class NuclearBomb {
public void on() {
System.out.println("Boom!");
}
}
如您所见,两者都有一个on()
方法。对于烤面包机,它开始烘烤。对于核弹来说,它会引发爆炸。哎呀:/现在想象一下你决定(不要问我为什么!)在两者之间创造一些东西。这样你就有了一MysteriousDevice
堂课! 当然,此代码不起作用,我们仅将其作为示例提供,“但它可能是”:
public class MysteriousDevice extends Toaster, NuclearBomb {
public static void main(String[] args) {
MysteriousDevice mysteriousDevice = new MysteriousDevice();
mysteriousDevice.on(); // So what should happen here? Do we get toast or a nuclear apocalypse?
}
}
让我们来看看我们有什么。这个神秘装置同时继承了 Toaster 和 NuclearBomb。两者都有on()
方法。因此,如果我们调用该on()
方法,则不清楚应该在MysteriousDevice
对象上调用哪个方法。对象不可能知道。最重要的是:NuclearBomb 没有off()
方法,所以如果我们没有猜对,就不可能禁用该设备。 
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
这是你的老朋友,班级Calendar
。它是抽象的,有几个孩子。其中之一是GregorianCalendar
。您已经在有关日期的课程中使用过它。:) 一切似乎都很清楚。只有一个问题:抽象类和接口之间的根本区别到底是什么?为什么他们将两者都添加到 Java 而不是将语言限制为一种?毕竟,那已经完全足够了。我们将在下一课讨论这个!直到那时 :)
更多阅读: |
---|
GO TO FULL VERSION