在前面的课程中,你已经屡次看到了继承,在Java语言中,类能够从其余类派生,从而从这些类继承字段和方法。html
定义:从另外一个类派生的类称为子类(也是派生类,扩展类或子类),派生子类的类称为超类(也是基类或父类)。java
除了Object
没有超类,每一个类都有一个且只有一个直接超类(单继承),在没有任何其余显式超类的状况下,每一个类都隐式地是Object
的子类。程序员
类能够从派生自类的类派生的类派生,依此类推,最终派生自最顶层的类,Object
,这样的类被称为继承链中全部向后延伸到Object
的类的子类。编程
继承的概念很简单但很强大:当你想要建立一个新类而且已经有一个包含你想要的一些代码的类时,你能够从现有类派生你的新类,在这样作时,你能够重用现有类的字段和方法,而无需本身编写(和调试)它们。segmentfault
子类从其超类继承全部成员(字段、方法和嵌套类),构造函数不是成员,所以它们不是由子类继承的,可是能够从子类调用超类的构造函数。api
在java.lang
包中定义的Object类定义并实现全部类共有的行为 — 包括你写的那些,在Java平台中,许多类直接从Object
派生,其余类派生自其中一些类,依此类推,造成类的层次结构。安全
在层次结构的顶部,Object
是全部类中最通用的,层次结构底部附近的类提供更专业的行为。oracle
下面是类和对象课程中提供的Bicycle
类的可能实现的示例代码:app
public class Bicycle { // the Bicycle class has three fields public int cadence; public int gear; public int speed; // the Bicycle class has one constructor public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; } // the Bicycle class has four methods 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; } }
做为Bicycle
的子类的MountainBike
类的类声明可能以下所示:编程语言
public class MountainBike extends Bicycle { // the MountainBike subclass adds one field public int seatHeight; // the MountainBike subclass has one constructor public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) { super(startCadence, startSpeed, startGear); seatHeight = startHeight; } // the MountainBike subclass adds one method public void setHeight(int newValue) { seatHeight = newValue; } }
MountainBike
继承了Bicycle
的全部字段和方法,并添加了字段seatHeight
和设置它的方法,除了构造函数以外,就好像你已经从头开始编写了一个新的MountainBike
类,有四个字段和五个方法。可是,你没必要完成全部工做,若是Bicycle
类中的方法很复杂而且须要花费大量时间来调试,那么这将特别有价值。
不管子类所在的包是什么,子类都会继承其父级的全部public
成员和protected
成员,若是子类与其父类在同一个包中,它还会继承父类的包私有成员,你能够按原样使用继承的成员,替换它们,隐藏它们或用新成员补充它们:
super
来调用超类的构造函数。本课程的如下部分将扩展这些主题。
子类不继承其父类的private
成员,可是,若是超类具备访问其私有字段的公共或受保护方法,则子类也可使用这些方法。
嵌套类能够访问其封闭类的全部私有成员 — 包括字段和方法,所以,子类继承的public
或protected
嵌套类能够间接访问超类的全部私有成员。
咱们已经看到一个对象是实例化它的类的数据类型,例如,若是咱们写
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
,以便咱们能够知道不会抛出运行时异常来进行转换。
类和接口之间的一个显着区别是类能够有字段而接口不能,此外,你能够实例化一个类来建立一个对象,这是你没法使用接口进行的,如什么是对象?部分所述,对象将其状态存储在字段中,这些字段在类中定义。Java编程语言不容许扩展多个类的一个缘由是避免了多重继承状态的问题,即从多个类继承字段的能力。例如,假设你可以定义一个扩展多个类的新类,经过实例化该类来建立对象时,该对象将继承全部类的超类中的字段,若是来自不一样超类的方法或构造函数实例化相同的字段会怎样?哪一个方法或构造函数优先?因为接口不包含字段,所以你没必要担忧多重继承状态所致使的问题。
实现的多重继承是从多个类继承方法定义的能力,这种类型的多重继承会出现问题,例如名称冲突和歧义,当支持这种类型的多继承的编程语言的编译器遇到包含具备相同名称的方法的超类时,它们有时没法肯定要访问或调用的成员或方法。此外,程序员能够经过向超类添加新方法而无心中引入名称冲突,默认方法引入了一种实现的多重继承形式,一个类能够实现多个接口,该接口能够包含具备相同名称的默认方法,Java编译器提供了一些规则来肯定特定类使用哪一种默认方法。
Java编程语言支持多种类型的继承,这是类实现多个接口的能力,对象能够有多种类型:它本身的类的类型以及该类实现的全部接口的类型。这意味着若是将变量声明为接口的类型,则其值能够引用从实现接口的任何类实例化的任何对象,这在将接口用做类型一节中讨论。
与多实现继承同样,一个类能够继承它扩展的接口中定义的方法的不一样实现(做为默认或静态),在这种状况下,编译器或用户必须决定使用哪个。
在类中,与超类中的字段具备相同名称的字段会隐藏超类的字段,即便它们的类型不一样,在子类中,超类中的字段不能经过其简单名称引用,相反,必须经过super
访问该字段,通常来讲,咱们不建议隐藏字段,由于它使代码难以阅读。
你能够声明一些或全部类的方法为final
,你在方法声明中使用final
关键字来指示子类不能重写该方法,Object
类这样作 — 它的一些方法是final
。
若是方法具备不该被更改的实现,而且对于对象的一致状态相当重要,则可能但愿将方法设为final
,例如,你可能但愿在此ChessAlgorithm
类中生成getFirstPlayer
方法:
class ChessAlgorithm { enum ChessPlayer { WHITE, BLACK } ... final ChessPlayer getFirstPlayer() { return ChessPlayer.WHITE; } ... }
从构造函数调用的方法一般应该声明为final
,若是构造函数调用非final
方法,子类可能会从新定义该方法,并产生意外或不但愿看到的结果。
请注意,你还能够声明整个类final
,声明为final
的类不能被子类化,这特别有用,例如,在建立String
类这样的不可变类时。
除了Object
类以外,一个类只有一个直接超类,类继承其全部超类中的字段和方法,不管是直接仍是间接,子类能够重写它继承的方法,也能够隐藏它继承的字段或方法(请注意,隐藏字段一般是糟糕的编程习惯)。
“覆盖和隐藏方法”部分中的表显示了使用与超类中的方法相同的签名声明方法的效果。
Object
类是类层次结构的顶部,全部类都是此类的后代,并从中继承方法,从Object
继承的有用方法包括toString()
、equals()
、clone()
和getClass()
。
你能够经过在类的声明中使用final
关键字来阻止类被子类化,一样,你能够经过将方法声明为final
方法来防止子类重写该方法。
抽象类只能被子类化,它没法实例化,抽象类能够包含抽象方法 — 声明但未实现的方法,而后,子类提供抽象方法的实现。