Encapsulation,Message Passing以及Inheritance是構成Object-Oriented的三大要素,如果某程式語言只具備前面兩項特性,一般成為Object-Based。所謂Inheritance(繼承),是指Sub Class(子類別)繼承Super Class(父類別)後,就會自動取得父類別特性。如果子類別繼承了一個以上的父類別,則稱為Multiple Inheritance(多重繼承)。Java為了避開多重繼承的複雜性, class只允許單一繼承。
Java使用關鍵字extends來表達繼承觀念:
public class Animal {
public String moveMethod() {
return "Unspecified";
public class Bird extends Animal {
public String moveMethod() {
return "Fly";
public class Dog extends Animal {
public String moveMethod() {
return "run";
public class Fish extends Animal {
public String moveMethod() {
return "swim";
若class宣告時沒有指定extends,則Java會自動extends java.lang.Object。
public class A {
和下面的寫法相同
public class A extends java.lang.Object {
UpCasting(向上轉型)和DownCasting(向下轉型)
所謂casting是指型態轉換, UpCasting是將子類別型態的reference轉型為父類別型態,
DownCasting則是將父類別型態的reference轉型成子類別型態。由於子類別可以視為和父類別相容,如Fish, Dog,
Bird都是一種Animal, 因此UpCasting一定沒有問題:
Animal a;
Bird b;
a = b; // upcasting, Bird is a kind of Animal
父類別的reference可以指到子類別的Object,這種觀念稱為Polymorphism(多型)。
但在downcasting的情況下, 父類別的reference和子類別並不相容,
如Animal不見得是一個Bird, 因此必須使用(SubClass)的casting語法來做強迫轉換。
Animal a = new Bird(); // upcasting
Bird b;
b = (Bird)a; // downcasting, compile correct
if (a instanceof Bird) { // true
downcasting除了必須由設計者下達外,
JVM在runtime也會檢查實際的物件能否和reference的型態相容
Animal a = new Dog(); // upcasting
Bird b;
b = (Bird) a; // downcasting, compile correct, but runtime error
比較完整的範例如下
public class InheritanceExample {
public static void main(String[] argv) {
Animal a1, a2, a3, a4;
Bird b;
Dog d;
Fish f;
a2 = a1 = new Animal();
b = new Bird();
d = new Dog();
f = new Fish();
System.out.println(a1.moveMethod());
System.out.println(b.moveMethod());
System.out.println(d.moveMethod());
System.out.println(f.moveMethod());
a1 = b; // Correct, we call this upcasting
b = a1; // Compile Error, type not compatible
b = (Bird)a1; // downcasting, Compile Correct
a2 = b; // Correct,we call this upcasting
d = a2; // Compile Error, type not compatible
d = (Dog)a2; // Compile Correct, but runtime error
Override(覆寫)
子類別重新定義它所能看到的父類別中的method(如public, protected,
如果子類別和父類別在同一個package裡, 則沒有修飾字的method也可以), 稱為override。
public class Animal {
public String moveMethod() {
return "Unspecified";
public class Bird extends Animal {
// override Animal's moveMethod
public String moveMethod() {
return "Fly";
要特別強調的是
如果子類別看不到父類別的方法(如父類別的private方法,或子父類別不在同一個package而子類別定義了父類別內的package method),則就算定義了同樣的method,也不是override
重複定義static method也不算override
子類別不可縮小父類別方法的存取範圍
public class C2 {
public void a() {}
public class C1 extends C2 {
protected void a() { // Compile Error,不得縮小存取範圍
Virtual Function(虛擬函數)
在訊息傳遞的章節裡,我們有提到過Object接收到訊息後,是在Runtime才決定實際所要呼叫的Method。由於父類別的reference可以指到子類別物件(Polymorphism),而子類別和父類別可能都定義了相同的Method(Override),當使用父類別reference傳遞訊息給子類別物件時,應該要呼叫父類別的方法還是子類別的方法? 如果
呼叫子類別的方法,則稱為Virtual Function
呼叫父類別的方法,則稱為Non-Virtual Function
有些程式語言,如C++,以上兩種機制都提供,可由設計者自行決定。但是Java語言為了遵循物件導向的精神,並避免設計者因語言設計複雜而犯錯,因此只提供了Virtual Function。
public class InheritanceExample {
public static void main(String[] argv) {
Animal a1;
a1 = new Animal();
System.out.println(a1.moveMethod()); // print out "Unspecified"
a1 = new Bird(); // polymorphism
System.out.println(a1.moveMethod()); // print out "Fly"
請注意上一小節所提到Override的注意事項
class Animal {
public static String moveMethod() {
return "Unspecified";
public static void main(String[] argv) {
Animal a1;
a1 = new Bird();
System.out.println(a1.moveMethod()); // print out "Unspecified"
class Bird extends Animal {
// we can't override static method
public static String moveMethod() {
return "Fly";
上面的moveMethod()由於宣告為static,因此是依照reference的type來決定執行的method。
class Animal {
private String moveMethod() {
return "Unspecified";
public static void main(String[] argv) {
Animal a1;
a1 = new Bird();
System.out.println(a1.moveMethod()); // print out "Unspecified"
class Bird extends Animal {
// this is not override because Bird can't see Animal's moveMethod
public String moveMethod() {
return "Fly";
由於上面Animal內的moveMethod宣告為private,因此執行時印出"Unspecified"。
採用Virtual Function的優點
Runtime自動尋找最特定的方法(儘量用子類別的方法),可用父類別reference呼叫到子類別的方法,因此增加新的子類別時,不需要修改程式
執行起來比較慢
本章觀念整理範例
public class Shape2D { // define super class
public double area() { // all Shape2D have their own area
return 0;
public class Rectangle extends Shape2D {
private double length, width;
public Rectangle(double l, double w) { // define constructor
length = l;
width = w;
public double area() { // Override
return length * width;
public class Circle extends Shape2D {
private double radius;
public Circle(double r) {
radius = r;
public double area() { // Override
return 3.141592654 * radius * radius;
public class Parallelogram extends Shape2D {
private double top, bottom, height;
public Parallelogram(double t, double b, double h) {
top = t;
bottom = b;
height = h;
public double area() { // Override
return (top + bottom) * height / 2.0;
publicclass Main {
public static double sum(Shape2D[] shapes) {
double total = 0;
for (int i = 0; i < shapes.length; i++) {
total += shapes[i].area(); // use Virtual Function to calculate area of Shape2D
// Without Virtual Function, value of Shape2D.area() will be 0
return total;
public static void main(String[] argv) {
Shape2D[] data; // array of reference to Shape2D
data = new Shape2D[5]; // create array object
data[0] = new Rectangle(2.4, 3.8); // Polymorphism
data[1] = new Circle(3.9);
data[2] = new Parallelogram(3.5, 6.7, 10.2);
data[3] = new Rectangle(5.3, 7.2);
data[4] = new Circle(4.6);
System.out.println("Sum of all Shape2D is "+sum(data));
如果程式語言不支援virtual function的話, 則上面的範例就得寫成下面的形式才行
public class Main { // example for non-virtual function implementation
public double sum(Shape2D[] shapes) {
double total = 0;
for (int i = 0; i < shapes.length; i++) {
if (shapes[i] instanceof Rectangle) {
total += ((Rectangle)shapes[i]).area();
} else if (shapes[i] instanceof Circle) {
total += ((Circle)shapes[i]).area();
} else if (shapes[i] instanceof Parallelogram) {
total += ((Parallelogram)shapes[i]).area();
} // modify source code here for new sub classes
return total;
public static void main(String[] argv) {
Shape2D[] data; // array of reference to Shape2D
data = new Shape2D[5]; // create array object
data[0] = new Rectangle(2.4, 3.8); // Polymorphism
data[1] = new Circle(3.9);
data[2] = new Parallelogram(3.5, 6.7, 10.2);
data[3] = new Rectangle(5.3, 7.2);
data[4] = new Circle(4.6);
System.out.println("Sum of all Shape2D is "+sum(data));
final修飾字
final除可用來修飾變數外,也可放在class和object method前面:
public final class FinalClass {
public final void finalMethod() {
放在class前面表示class不可被繼承, 放在object method表示不可被Override。
繼承關係下的Constructor執行順序
先將所有變數設為內定值。對數值型態來說,其值為0; 對reference來說,其值為null; 對boolean來說,其值為false。
呼叫父類別的constructor。如果子類別Constructor裡沒有指定父類別的Constructor, 則使用父類別沒有參數的Constructor。
執行變數宣告的初始化動作。
執行自己的constructor。
如果要指定父類別其他的constructor,則必須在子類別的constructor的第一行使用關鍵字super來處理。
class Animal {
int aMask = 0x00FF;
public Animal() {
public Animal(int mask) {
aMask = mask;
public class Bird extends Animal {
int bMask = 0xFF00;
int fullMask;
public Bird() {
// Compiler add super() here
fullMask = bMask | aMask;
public Bird(int mask) {
/* 若有super,則必須放在第一行,連變數宣告也不能擺在super前面 */
super(mask);
fullMask = bMask | aMask;
public static void main(String[] argv) {
Bird b = new Bird();
System.out.println(b.fullMask);
b = new Bird(0x0011);
System.out.println(b.fullMask);
當執行new Bird()時,此物件內各個變數的變化如下
步驟aMaskbMaskfullMask
default000
call Bird()000
call Animal()000
Animal initialize0x00FF00
execute Animal()0x00FF00
Bird initialize0x00FF0xFF000
execute Bird()0x00FF0xFF000xFFFF
當執行new Bird(0x0011)時,此物件內各個變數的變化如下
步驟aMaskbMaskfullMask
default000
call Bird(0x0011)000
call Animal(0x0011)000
Animal initialize0x00FF00