【练习7-1(TruckDemo.java)】扩展Vehicle类
为演示继承的强大功能,我们将扩展在第4章中最先开发的Vehicle类。它封装了汽车的信息,包括乘载人数、油箱容量和燃油利用率。我们可以把Vehicle类作为起点来创建更具体的类。例如,卡车是汽车的一种。卡车的一个重要属性就是它的运载能力。因此要创建Truck类,可扩展Vehicle类,添加存储运载能力的实例变量。下面的Truck类实现了这一点。在实现过程中,Vehicle类中的实例变量将被设为private,并提供访问器方法来获取或设置它们的值。
java
package javaone.a.beginners.guide.chapterseven;
// Try This 7-1
//
// Build a subclass of Vehicle for trucks/
class Vehicle{
private int passengers; // number of passengers
private int fuelcap; // fuel capacity in gallons
private int mpg; // fuel consumption in miles per gallon
// This is a constructor for Vehicle
Vehicle(int p, int f, int m){
passengers = p;
fuelcap = f;
mpg = m;
}
// Return the range
int range(){
return mpg * fuelcap;
}
// Compute fuel needed for a given distance
double fuelneeded(int miles){
return (double) miles / mpg;
}
// Accessor methods for instance variables.
public int getPassengers() {
return passengers;
}
public void setPassengers(int passengers) {
this.passengers = passengers;
}
public int getFuelcap() {
return fuelcap;
}
public void setFuelcap(int fuelcap) {
this.fuelcap = fuelcap;
}
public int getMpg() {
return mpg;
}
public void setMpg(int mpg) {
this.mpg = mpg;
}
}
// Extend Vehicle to create a Truck specialization
class Truck extends Vehicle{
private int cargocap; // cargo capacity in pounds
// This is a constructor for Truck
Truck(int p, int f, int m, int c){
/*
Initialize Vehicle members using Vehicle's constructor.
*/
super(p,f,m);
cargocap = c;
}
// Accessor methods for cargocap.
int getCargo(){
return cargocap;
}
void putCargo(int c){
cargocap = c;
}
}
public class ChapterSevenProgramOne {
public static void main(String[] args) {
// construct some trucks
Truck semi = new Truck(2, 200, 7, 44000);
Truck pickup = new Truck(3, 28, 15, 2000);
double gallons;
int dist = 252;
gallons = semi.fuelneeded(dist);
System.out.println("Semi can carry " + semi.getCargo() + " pounds.");
System.out.println("To go " + dist + " miles semi needs " + gallons + " gallons of fuel.\n");
gallons = pickup.fuelneeded(dist);
System.out.println("Pickup can carry " + pickup.getCargo() + " pounds.");
System.out.println("To go " + dist + " miles pick up needs " + gallons + " gallons of fuel.\n");
}
}
7.15 自测题
- 超类有权访问子类的成员吗?子类有权访问超类的成员吗?
答案:没有,超类不知道子类的存在。子类可以访问超类的任何非私有成员。
- 创建一个名为Circle的TwoDShape的子类,它包括一个计算圆面积的area方法和一个使用super初始化TwoDShape部分的构造函数。
java
package javaone.a.beginners.guide.chapterseven;
class TwoDShapeTen{
private double width;
private double height;
private String name;
// A default constructor.
TwoDShapeTen(){
width = height = 0.0;
name = "none";
}
// Parameterized constructor.
TwoDShapeTen(double w, double h, String n){
width = w;
height = h;
name = n;
}
// Construct object with equal width and height.
TwoDShapeTen(double x, String n){
width = height = x;
name = n;
}
// Construct an object from an object.
TwoDShapeTen(TwoDShapeTen ob){
width = ob.width;
height = ob.height;
name = ob.name;
}
// Accessor methods for width and height.
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
String getName() {
return name;
}
void showDim(){
System.out.println("Width and height are " + width + " and " + height);
}
double area(){
System.out.println("area() must be overridden");
return 0.0;
}
}
// A subclass of TwoDShape for circles.
class Circle extends TwoDShapeTen{
// A default constructor.
Circle(){
super();
}
// Construct Circle
Circle(double x){
super(x, "circle"); // call superclass constructor
}
// Construct an object from an object.
Circle(Circle ob){
super(ob); // pass object to TwoDShape constructor
}
double area(){
return (getWidth() / 2) * (getWidth() / 2) * 3.14;
}
}
public class ChapterSevenExerciseTwo {
}
- 如何防止子类访问超类的成员?
答案:可以把超类的成员声明为私有的。
- 描述本章中两个super版本的目的及用法。
答案:super关键字具有两种形式。第一种用来调用超类的构造函数,其基本形式如下:
super(param-list);
第二种用来访问超类的成员,其基本形式如下:
super.member
- 已知层次结构如下:
class Alpha { ...
class Beta extends Alpha { ...
class Gamma extends Beta { ...
当初始化一个Gamma对象时,这些类的构造函数的调用顺序是什么?
答案:构造函数总是按照派生的顺序被调用,因此,当创建Gamma对象时,调用顺序是Alpha、Beta、Gamma。
- 超类引用可以引用一个子类对象。解释为什么当它与方法重写相关时,这一点变得特别有用?
答案: 当重写的方法通过超类引用调用时,可通过被引用的对象的类型来判断调用哪一个版本的方法。
- 什么是抽象类?
答案:
有时,需要创建一个这样的超类:该超类只定义一个为所有子类共享的一般形式,至于细节则交给每个子类去填充。
Java对于这一问题的解决方法是抽象方法(abstract method)。抽象方法是通过指定abstract类型修饰符来创建的。
包含一个或多个抽象方法的类必须通过在其class声明前添加abstract修饰符来将其声明为抽象类。
- 如何使方法不被重写? 如何使类不被继承?
答案:要防止方法被重写,可将它声明为final。要防止类被继承,也可将它声明为final。
- 解释继承、方法重写和抽象类是如何支持多态的。
答案:继承、方法重写和抽象类是这样支持多态的:允许创建可由各种类实现的通用类结构。这样,抽象类就可以定义由所有实现的类共享一致的接口。这样做就实现了"一个接口,多个方法。"
- 什么类是其他所有类的超类?
答案:Object类。
- 包含至少一个抽象方法的类必须声明为抽象类,对吗?
答案: 是的。
- 用于创建已命名常量的关键字是什么?
答案:final。