Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
有关Java SE 9及后续版本中更新的语言功能的摘要,请参见Java语言更改。
有关所有JDK版本的新功能、增强功能以及已删除或不建议使用的选项的信息,请参见JDK发行说明。
在前面的课程中,你已经多次看到了继承的提及。在Java语言中,类可以从其他类派生,从而继承这些类的字段和方法。
Object没有超类外,每个类只有一个直接超类(单一继承)。在没有其他显式超类的情况下,每个类都隐式地是Object的子类。
Object派生。这样的类被称为从继承链中的所有类中派生到Object。
继承的思想简单而强大:当你想要创建一个新类,并且已经存在一个包含你想要的一些代码的类时,你可以从现有类派生出你的新类。通过这样做,你可以重用现有类的字段和方法,而无需自己编写(和调试!)它们。
子类从其超类继承所有的成员(字段、方法和嵌套类)。构造函数不是成员,因此它们不会被子类继承,但是可以从子类中调用超类的构造函数。
在Java平台中,Object类在java.lang包中定义和实现了所有类的共同行为,包括你编写的类。许多类直接从Object派生,其他类从其中一些类派生,依此类推,形成了一个类的层次结构。
Java平台中的所有类都是Object的子类
在层次结构的顶部,Object是所有类中最通用的类。层次结构底部的类提供了更专门的行为。
下面是一个可能的实现一个Bicycle类的示例代码,它在“类和对象”课程中进行了介绍:
public class Bicycle {
// Bicycle类有三个字段
public int cadence;
public int gear;
public int speed;
// Bicycle类有一个构造函数
public Bicycle(int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
// Bicycle类有四个方法
public void setCadence(int newValue) {
cadence = newValue;
}
public void setGear(int newValue) {
gear = newValue;
}
public void applyBrake(int decrement) {
speed -= decrement;
}
public void speedUp(int increment) {
speed += increment;
}
}
一个MountainBike类的声明,它是Bicycle类的子类,可能如下所示:
public class MountainBike extends Bicycle {
// MountainBike子类添加一个字段
public int seatHeight;
// MountainBike子类有一个构造函数
public MountainBike(int startHeight,
int startCadence,
int startSpeed,
int startGear) {
super(startCadence, startSpeed, startGear);
seatHeight = startHeight;
}
// MountainBike子类添加一个方法
public void setHeight(int newValue) {
seatHeight = newValue;
}
}
MountainBike继承了Bicycle的所有字段和方法,并添加了seatHeight字段和一个设置它的方法。除了构造函数外,就好像你从头开始写了一个新的MountainBike类,有四个字段和五个方法。然而,你并不需要做所有的工作。如果Bicycle类中的方法很复杂且需要大量时间来调试,这将特别有价值。
子类继承了其父类的所有公共和受保护的成员,无论子类在哪个包中。如果子类与其父类在同一个包中,它还会继承父类的包私有成员。你可以直接使用继承的成员,替换它们,隐藏它们,或者补充它们的新成员:
super关键字调用父类的构造函数。本课程的以下章节将详细介绍这些主题。
子类不会继承其父类的private成员。然而,如果父类有用于访问其私有字段的公共或受保护方法,子类也可以使用这些方法。
嵌套类可以访问其封闭类的所有私有成员,包括字段和方法。因此,子类继承的公共或受保护的嵌套类间接地访问了父类的所有私有成员。
我们已经了解到,对象的数据类型是其实例化的类的类型。例如,如果我们写下:
public MountainBike myBike = new MountainBike();
那么myBike的类型就是MountainBike。
MountainBike是从Bicycle和Object继承而来的。因此,MountainBike既是Bicycle,也是Object,它可以在需要Bicycle或Object对象的任何地方使用。
反过来则不一定成立:一个Bicycle可能是一个MountainBike,但也可能不是。同样,一个Object可能是一个Bicycle或MountainBike,但也可能不是。
类型转换是在继承和实现允许的对象类型之间使用一个类型的对象来替代另一个类型的对象。例如,如果我们写下:
Object obj = new MountainBike();
那么obj既是一个Object,也是一个MountainBike(直到obj被赋予另一个不是MountainBike的对象为止)。这被称为隐式类型转换。
然而,如果我们写下:
MountainBike myBike = obj;
我们将得到一个编译时错误,因为编译器不知道obj是一个MountainBike。然而,我们可以通过显式类型转换告诉编译器,我们承诺将一个MountainBike赋给obj:
MountainBike myBike = (MountainBike)obj;
这个类型转换会在运行时检查obj是否被赋予了一个MountainBike,以便编译器可以安全地假设obj是一个MountainBike。如果运行时obj不是一个MountainBike,就会抛出异常。
instanceof操作符对特定对象的类型进行逻辑测试。这可以避免由于错误的类型转换而导致运行时错误。例如:
if (obj instanceof MountainBike) {
MountainBike myBike = (MountainBike)obj;
}
这里的instanceof操作符验证obj是否引用了一个MountainBike,以便我们可以在进行转换时知道不会抛出运行时异常。