一、抽象方法和抽象类
1.抽象方法:在方法前加abstract修饰。只有方法的声明,没有方法的实现。
(1)作用:为子类提供统一接口。
(2)格式:
abstract ReturnType MethodName();
2.抽象类:在类前加abstract修饰。抽象类中可以有抽象方法和非抽象方法。
(1)抽象类不能被实例化,即不能有抽象类的对象。
(2)抽象类的子类仍可以是抽象类。
(3)final和abstract不能同时修饰一个类,因为final不能被继承,abstract类必须被继承。
(4)抽象类的子类必须实现抽象类的所有方法,不然它也要被定义为抽象类。所以类中有抽象方法的类就是抽象类。
二、程序实例:
package com.nine;//: c07:music4:Music4.java
// From 'Thinking in Java, 2nd ed.' by Bruce Eckel
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
// Abstract classes and methods.
import java.util.*;
abstract class Instrument { //基类
int i; // storage allocated for each
public abstract void play(); //play方法抽象
public String what() {
return "Instrument";
}
public abstract void adjust(); //adjust方法抽象
}
class Wind extends Instrument { //子类1
public void play() {
System.out.println("Wind.play()");
}
public String what() { return "Wind"; }
public void adjust() {}
}
class Percussion extends Instrument { //子类2
public void play() {
System.out.println("Percussion.play()");
}
public String what() { return "Percussion"; }
public void adjust() {}
}
class Stringed extends Instrument { //子类3
public void play() {
System.out.println("Stringed.play()");
}
public String what() { return "Stringed"; }
public void adjust() {}
}
class Brass extends Wind { //wind的子类1
public void play() {
System.out.println("Brass.play()");
}
public void adjust() {
System.out.println("Brass.adjust()");
}
}
class Woodwind extends Wind { //wind的子类2
public void play() {
System.out.println("Woodwind.play()");
}
public String what() { return "Woodwind"; }
}
public class Music4 {
// Doesn't care about type, so new types
// added to the system still work right:
static void tune(Instrument i) {
// ...
i.play();
}
static void tuneAll(Instrument[] e) {
for(int i = 0; i < e.length; i++)
tune(e[i]);
}
public static void main(String[] args) {
Instrument[] orchestra = new Instrument[5];
int i = 0;
// Upcasting during addition to the array:
orchestra[i++] = new Wind();
orchestra[i++] = new Percussion();
orchestra[i++] = new Stringed();
orchestra[i++] = new Brass();
orchestra[i++] = new Woodwind();
tuneAll(orchestra);
}
}
输出为:
Wind.play()
Percussion.play()
Stringed.play()
Brass.play()
Woodwind.play()
通过这个程序再说一下方法调用:
对重载的方法,java虚拟机根据传递给方法的参数个数和类型(即参数列表)确定调用哪个方法;对覆盖的方法,java的运行时系统根据实例类型决定调用哪个方法;对于子类的一个实例,如果子类覆盖了超类的方法,运行时系统执行子类的方法,如果子类继承了超类的方法,则运行时系统执行超类的方法。
讨论一下下面的代码:
static void tune(Instrument i) {
// ...
i.play();
}
static void tuneAll(Instrument[] e) {
for(int i = 0; i < e.length; i++)
tune(e[i]);
这里其实体现了抽象的好处,即调用play方法时,系统根据对象的实际类型调用相应的play方法,如果以后再加一个Instrument的子类,程序不用修改。提高了程序的可维护性和可扩展性。
参考资料:
《java语言程序设计》——清华大学出版社
《java编程思想》——机械工业出版社