学习目标:
1)学习继承并实现子类override方法
2)理解多态polymorphism的概念
3)熟悉common superclass Object 和它的 methods
4)学习interface types
Chapter 9.1 Inheritance Hierarchies
来自相关类的对象通常具有共同的行为。例如,铲子、耙子和剪刀都执行园艺任务。 在本章中,您将学习继承的概念如何表达专用类和通用类之间的关系。通过使用继承,您将能够在类之间共享代码并提供可供多个类使用的服务。
在面向对象的设计中,继承是更通用的类(称为超类)和更专业的类(称为子类)之间的关系。子类 subclass 从超类 superclass. 继承数据和行为。
假设我们有一个操作 Vehicle 对象的算法。因为汽车是一种特殊的交通工具,我们可以在这样的算法中使用 Car 对象,它会正常工作。 替换原则指出,当需要超类对象时,您始终可以使用子类对象。 例如,考虑一个采用 Vehicle 类型参数的方法:
void processVehicle(Vehicle v)
因为 Car 是 Vehicle 的子类,所以您可以使用 Car 对象调用该方法:
Car myCar = new Car(. . .);
processVehicle(myCar);
为什么要提供一种处理 Vehicle 对象而不是 Car 对象的方法? 该方法更有用,因为它可以处理任何类型的车辆(包括卡车和摩托车对象)。通常,当我们将类分组到继承层次结构中时,我们可以在类之间共享公共代码。
代码实例:
在本章中,我们将考虑一个简单的类层次结构。 假设您参加了计算机分级测验,测验由不同类型问题组成:填空,选择(单选或多选),数字填空,简答题。
此层次结构的根 root 是Question。 Question可以显示其题目内容,并且可以检查输入的回答是否是正确答案。
为了打代码熟练点我手打了一下书上代码(
package chapter9;
public class Question {
private String text;
private String answer;
public Question(){
text = "";
answer = "";
}
public void setText(String questionText){
text = questionText;
}
public void setAnswer(String correctResponse){
answer = correctResponse;
}
public boolean checkAnswer(String response){
return response.equals(answer);
}
public void display(){
System.out.println(text);
}
}
Question类比较基础,不处理多项选择题、数字题等,下面附了一个 Question 类的简单测试程序。
package chapter9;
import java.util.Scanner;
public class QuestionTester {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Question q = new Question();
q.setText("Who's the inventor of Java?");
q.setAnswer("James Gosling");
q.display();
System.out.println("Your answer:");
String response = in.nextLine();
System.out.println(q.checkAnswer(response));
}
}
运行结果是这样的:
tips:使用单个类来改变值,使用继承来改变行为。
Chapter 9.2 Implementing Subclasses
how to form a subclass and how a subclass automatically inherits functionality from its superclass.
在9.1的Question类基础上实现 ChoiceQuestion 类,其中包含设置问题、显示问题和检查答案的方法。子类对象自动具有在超类中声明的实例变量,只需要声明不属于超类对象的实例变量。
子类继承了超类的所有 public 方法。 可以声明子类的任何新方法,如果继承的 method 不合适,则更改继承 method 的实现。 当您为继承的方法提供新的实现时,您将override该方法。
ChoiceQuestion 对象在三个方面与 Question 对象不同:1) 需要存储题目的各种选择。2) 需要一种添加题目选项的方法。3) ChoiceQuestion 类的 display 方法需要显示这些选项,以便 visitor 可以选择其中之一。
保留字 extends 表示继承。
但是,超类的 provate 实例变量是不可访问的。因为这些变量是超类的私有数据,所以只有超类可以访问它们。子类没有比任何其他类更多的访问权限。特别是,ChoiceQuestion 方法不能直接访问实例变量 answer。 这些方法必须使用 Question 类的公共接口来访问其私有数据,就像所有其他方法一样。
package chapter9;
import java.util.ArrayList;
public class ChoiceQuestion extends Question{
private ArrayList<String> choices;
public void addChoice(String choice, boolean correct){
choices.add(choice);
if(correct){
String choiceString = "" + choices.size();
setAnswer(choiceString);
}
}
public void display(){
// 还没写
}
}
您不能只访问超类中的 answer 变量。 幸运的是, Question 类有一个 setAnswer 方法。 你可以调用那个方法。
Chapter 9.3 Overriding Methods
子类继承了超类的 method。 如果您对继承的 method 不满意,您可以通过在子类中覆盖重写(override)它。
ChoiceQuestion 类的 display method 需要被重写覆盖,扩展超类的功能。该 method 需要显示题干和显示答案选项两项功能。
但是如何获得题干:不能直接访问超类的 text 变量,因为它是 private 的。但可以使用保留字 super 调用超类的 display 方法。如果省略保留字 super,则该 method 将无法按预期工作。
public void display(){
// question text
super.display();
// question choices
for(int i = 0; i < choices.size(); i++){
int choiceNumber = i + 1;
System.out.println(choiceNumber + ":" + choices.get(i));
}
}
附上一个Test程序:
package chapter9;
import java.util.ArrayList;
public class ChoiceQuestion extends Question{
private ArrayList<String> choices;
public ChoiceQuestion(){
choices = new ArrayList<>();
}
public void addChoice(String choice, boolean correct){
choices.add(choice);
if(correct){
String choiceString = "" + choices.size();
setAnswer(choiceString);
}
}
public void display(){
// question text
super.display();
// question choices
for(int i = 0; i < choices.size(); i++){
int choiceNumber = i + 1;
System.out.println(choiceNumber + ":" + choices.get(i));
}
}
}
package chapter9;
import java.util.Scanner;
public class QuestionTester2 {
public static void main(String[] args) {
ChoiceQuestion first = new ChoiceQuestion();
first.setText("What was the original name of the Java language?");
first.addChoice("*7", false);
first.addChoice("Duke",false);
first.addChoice("Oak", true);
first.addChoice("Gosling", false);
presentQuestion(first);
}
public static void presentQuestion(ChoiceQuestion q){
q.display();
System.out.println("Your answer:");
Scanner in = new Scanner(System.in);
String response = in.nextLine();
System.out.println(q.checkAnswer(response));
}
}
运行结果如下: