封裝、多態和繼承是面向對象編程的三大特性。
封裝(Encapsulation)
封裝的目的是爲了保證變量的安全性,使用者不必在意具體實現細節,而只是通過外部接口即可訪問類的成員
如果不進行封裝,類中的實例變量可以直接查看和修改,可能給整個代碼帶來不好的影響
因此在編寫類時一般將成員變量私有化,外部類需要同getter和setter方法來查看和設置變量
繼承(Inherit)
繼承實際上也是爲了提高代碼的複用性和可擴展性,在定義不同類的時候存在一些相同屬性,爲了方便使用可以將這些共同屬性抽象成一個父類,在定義其他子類時可以繼承自該父類,減少代碼的重複定義,子類可以使用父類中非私有的成員。
定義繼承的格式如下:
class 子類 extends 父類 { }
可以用以下例子表示:
public class Fu {
public void show() {
System.out.println("父類中的show方法被調用");
}
public void method() {
System.out.println("父類中的method方法被調用");
}
}
public class Zi extends Fu {
@override
public void method() {
System.out.println("子類中的method方法被調用");
}
}
public class Demo {
public static void main(String[] args) {
//創建對象,調用方法
Fu f = new Fu();
f.show(); // 父類中的show方法被調用
Zi z = new Zi();
z.method(); // 子類中的show方法被調用
z.show(); // 父類中的show方法被調用
}
}
在以上代碼中,Zi繼承自Fu,在Zi類中重寫了Fu類中的method方法,Zi類在執行method方法時執行的是重寫的方法,在執行show方法時執行的是Fu類中的方法。由此可得:如果子類對父類中方法進行了重寫,子類在調用該方法時執行的是重寫後的方法。
除此之外,子類中還可以定義新的變量和方法
在使用繼承關係時,不僅是單層繼承,一般會形成一個層次關係明顯的繼承樹,以定義狼來說,其父類可以有犬類和動物類,下圖用一個稍微複雜一點的例子顯示了他們之間的關係,在Java API中,大部分的繼承關係都不會超過三層
繼承中需要注意:
-
父類可以不知道他有哪些子類,但是子類必須明確他有哪些父類
-
子類在重寫父類時,如果想在父類功能基礎上增加新的功能,可以用super實現,如:
-
public void roam(){ // 父類中的方法 super.roam(); // 新增的行爲 new stuff; }
-
-
不能作爲繼承的子類:
- 存取控制
- 使用final修飾符,防止父類方法被重寫一般就是添加final修飾符
- 只有private構造方法
-
子類的參數的個數和類型要和父類完全一致,返回類型要兼容
-
子類中方法的存取權限只能改爲更低,不能高於父類中方法的存取權限
多態(Polymorphism)
多態指的是同一個對象可以表現出多種形態,通俗來說就是一個對象的引用類型既可以是實際類也可以是實際類的父類。
下面一個代碼實例可以直觀表示
public class Animal {
public int age = 40;
public void eat() {
System.out.println("動物吃東西");
}
}
public class Cat extends Animal {
public int age = 20;
public int weight = 10;
@Override
public void eat() {
System.out.println("貓吃魚");
}
public void playGame() {
System.out.println("貓捉迷藏");
}
}
public class AnimalDemo {
public static void main(String[] args) {
//有父類引用指向子類對象
Animal a = new Cat();
Cat c = new Cat();
System.out.println(a.age); // 40
System.out.println(((Cat) a).age); // 20
System.out.println(((Cat) a).weight); // 10
System.out.println(c.age); // 20
System.out.println(a.weight); // 10
}
}
此外,多態還可以應用到參數和返回類型中,如下代碼
class Vet{
public void giveShot(Animal a){
a.makeNoise();
}
}
class PetOwner{
public void start(){
Vet v = new Ver();
Dog d = new Dog();
Hippo h = new Hippo();
v.getShot(d); //調用Dog類中的makeNoise方法
v.getShot(h); //調用Hippo類中的makeNoise方法
}
}
方法重寫(override)和重載(overload)的區別
方法重載:方法重載指的是同一個類中定義多個同名方法,這些同名方法的參數個數和類型不同,返回類型和存取權限可以不同
方法重寫:方法重寫指的是有繼承關係的子類繼承父類中的方法並定義不同的方法體,子類和父類中的方法名和參數個數類型要完全一樣,是一種覆蓋。