Java 繼承(inheritance)是 Java 面向對象的三大重要特性之一(封裝-encapsulation, 繼承-inheritance, 多態-polymorphsim) Java 繼承很好的管理了具有相似特徵的類之間的關係(主要集中在成員變量、方法), 使程序可擴展、易修改,並且成爲java多態的基礎。下面將介紹Java繼承的基本語法以及特性:
1. 使用extends關鍵字實現類與類之間的繼承
public class parent {
}
public class child extends parent {
}
在這段代碼中,我們首先聲明瞭一個名叫parent的類。然後聲明瞭一個child類extends parent類作爲parent的子類,這時候parent類就被用作了父類(super class)。事實上,任何類都可以被用作父類,只要我們爲其聲明子類,不管它是否是抽象類(abstract class)。 在我們不重寫(overwrite) 或重載(override)父類中的方法、不增添新的方法、不更改原始的成員變量或增加新的變量的情況下,子類將默認保留父類的特性。2. 關於抽象類的繼承
對於一個抽象類,如果裏面包含有未實現的抽象方法並且我們想創造一個子類繼承這個抽象類,這個子類不必重寫(overwrite)抽象類中所有未實現的抽象方法,但是必須被定義爲抽象類。同理,如果一個類實現一個接口(Interface),那麼它要麼重寫接口裏的所有抽象方法,要麼被定義爲抽象類。
3. 關於父類與子類構造器的調用
父類與子類均爲默認構造器:
public class parent {
}
public class child extends parent {
}
在如上代碼中,父類與子類均調用super class Object的構造器(constructor)。需要注意的是,當我們使用“new”關鍵字新建子類child對象時,同時會調用父類parent的構造器並新建一個父類對象(parent對象)父類與子類均不爲默認構造器:
public class parent{
public parent (int m) {
}
}
public class child extends parent {
public child (int m, String a) {
super(m);
}
}
在這種情況下,子類必須重寫(overwrite)或重載(override)父類的構造函數,同時必須調用父類的構造器(constructor),因爲父類不再有默認的構造器可供調用。
4. Java單繼承的特性
在java中,一個父類被多個子類繼承,但一個子類只能繼承一個父類。與接口不同的是,一個類可以實現(implement)多個接口。
5. 創建子類或父類的對象
我們看下面這段代碼:
public class demo {
public static void main (String[] args) {
parent p = new parent();
child c = new child();
parent pc = new child();
}
}
public class parent {
}
public class child extends parent {
}
對於main方法中的前兩行,我們可以很容易的看出它新建了一個子類的對象和一個父類的對象,對於第三行這種,叫做父類的引用指向子類的對象,我們下邊分別來分析對於三種聲明的成員變量和方法的調用。實例方法(instance method)和實例變量(instance method)的調用:
針對p和c,這個類裏面有什麼實例方法和實例變量,那麼就允許調用什麼
針對pc,編譯器首先會在父類中進行搜索,如果搜索到,則不會報錯,此時再去看子類中有沒有重寫此方法或改變此變量。如果有,則調用子類的。如果被調用的方法或變量只在子類中有而在父類中沒有,那麼編譯器會報錯。
靜態方法(static method)和靜態變量(static variable)的調用:
針對p和c,這個類裏面有什麼實例方法和實例變量,那麼就允許調用什麼
針對pc,同理,只有在父類中存在,編譯器纔不會報錯。但是,即使子類重寫了父類的靜態方法,調用時依然會使用父類的靜態方法(在理論上,不建議通過objectName.method或objectName.variable的方式調用靜態方法或變量,最好使用className.method或className.variable的方法調用)
Java 多態
多態是同一個行爲具有多個不同表現形式或形態的能力。
多態就是同一個接口,使用不同的實例而執行不同操作,如圖所示:
對於多態,可以總結以下幾點:
一、使用父類類型的引用指向子類的對象;
二、該引用只能調用父類中定義的方法和變量;
三、如果子類中重寫了父類中的一個方法,那麼在調用這個方法的時候,將會調用子類中的這個方法;(動態連接、動態調用);
四、變量不能被重寫(覆蓋),"重寫"的概念只針對方法,如果在子類中"重寫"了父類中的變量,那麼在編譯時會報錯。
類的屬性變量是能重寫(覆蓋)
class Animal{ public int age; public void move(){ System.out.println("動物可以移動"); } } class Dog extends Animal{ public double age; public void move(){ age = 10.00; System.out.println("狗可以跑和走"); } public void bark(){ System.out.println("狗可以吠叫"); } } class Cat extends Animal{ public void move(){ super.age = 3; System.out.println("貓可以跳"); } } public class TestOverride{ public static void main(String args[]){ Animal a = new Animal(); // Animal 對象 Animal b = new Dog(); // Dog 對象 Dog c = new Dog(); Cat d = new Cat(); a.move();// 執行 Animal 類的方法 b.move();//執行 Dog 類的方法 c.move();//執行 Dog 類的方法 d.move();//執行 Cat 類的方法 Object aValue = a.age; Object bValue = b.age; Object cValue = c.age; System.out.println("The type of "+a.age+" is "+(aValue instanceof Double ? "double" : (aValue instanceof Integer ? "int" : ""))); System.out.println("The type of "+b.age+" is "+(bValue instanceof Double ? "double" : (bValue instanceof Integer ? "int" : ""))); System.out.println("The type of "+c.age+" is "+(cValue instanceof Double ? "double" : (cValue instanceof Integer ? "int" : "")));// 覆蓋age屬性 System.out.println("The age of cat is "+d.age); } }
編譯值:
動物可以移動 狗可以跑和走 狗可以跑和走 貓可以跳 The type of 0 is int The type of 0 is int The type of 10.0 is double The age of cat is 3