Java學習筆記——類與對象(封裝、繼承與多態)

        類與對象是在OO變成裏面經常出現的字眼,簡單的可以理解爲類是一類對象的抽象,對象是某一個類的具體實現。面向對象的編程,其實主要就體現在封裝、繼承與多態這三個方面。下面將逐個的介紹這三個名詞。

一、封裝

        面向對象裏面類的提出就是爲了實現封裝,我們將一類同樣的對象的一些相同或相似的屬性及方法抽象出來,封裝在一起就實現了封裝。封裝的目的就是爲了實現一些數據及方法的內部隱藏(通過修飾符來實現),並提供一些通用的方法供外部使用,而具體的內部實現細節無需對外公開,加強了安全性。封裝類要注意一下幾點:

  1. 類裏面一般都要提供一個或多個構造函數,構造函數可以重載。一旦提供了有參數的構造函數,那麼最好提供一個無參的構造函數,即使是空函數也好。因爲下面講到的繼承發生時,總是先運行父類的構造函數,如果需要運行無參的父類構造函數而找不到的話就會報錯。
  2. 在類裏面可以通過this關鍵字來指向自身。
  3. 類裏的屬性一般都設置成private隱藏,如果需要外部訪問或設置,可以通過get/set方法實現。

比如我封裝了一個汽車類Car,供後面使用,示例代碼如下:

package com.mct.main;
public class Car {
	protected String name;  // 一般不將類的屬性設置爲public,這裏設置爲protected,因爲這兩個屬性肯定是需要被子類繼承的。
	protected String color;
	public String getName() {  // 通過get,set方法讓外部訪問並設置屬性。
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public Car(){}  // 如果提供了有參數的構造函數,則最好再提供一個無參的構造函數,即使是空函數也好。	
	public Car(String name, String color){
		this.name = name;
		this.color = color;
	}	
	public void speedUp(){
		System.out.println("運行這裏加速 ");
	}	
	public void speedDown(){
		System.out.println("運行這裏減速");
	}
}


二、繼承

        繼承是使用已經存在的類爲基礎實現新的類,繼承使用extends關鍵字。在Java裏面只允許實現單繼承,子類將完全繼承父類中允許繼承的屬性和方法(具體依據修飾符的訪問權限而定),另外子類也可添加自己的屬性和方法,但不能選擇性的繼承父類。如果父類的某些功能無法滿足子類要求,可以使用下面要講到的覆寫或重載(有些著作中認爲父類與子類之間不存在重載關係)的方法來實現自己特有的方法。關於繼承需要注意一下幾點:

  1. 子類的構造方法一定會調用父類的構造方法。如果子類沒有顯式的調用父類的構造方法,那麼將默認調用父類的無參方法(這就是上面說的需要添加無參構造的原因)。當然構造方法如果不實現,則系統會默認提供一個無參構造方法。另外子類的構造方法中可以通過super()方法調用父類的某個構造方法,也可以通過this()方法調用本類中的某個構造方法,這兩種方式的調用語句都必須位於構造函數的第一行,所以它們是無法並存的。
  2. 父類構造方法是無法被繼承的,只能通過在子類中使用super來調用。
  3. Java中所有的類都直接或間接的繼承自Object類。如上面的Car沒有通過extends關鍵字繼承,那麼系統 會默認給其添加上extends Object,讓它繼承自Object類。
  4. 子類對象的引用可以通過僞裝賦值給父類對象的引用,無需進行類型轉換;而父類對象引用需要賦值給子類對象時需要經過強制類型轉換,當然前提是這個對象在構造時就是此子類類型,否則運行時肯定會因爲類型不匹配而報錯。這裏對一個對象引用的類型檢查使用 instanceof關鍵字。
  5. 說到繼承就不得不說一下抽象類和抽象方法,Java中使用abstract關鍵字修飾。抽象方法時一個沒有類體的方法,它用來描述某種功能或行爲,但具體的實現過程需要子類來實現。而抽象類一般都做爲某個功能或行爲的超類出現,抽象類無法實例化對象,只能被繼承。面向對象編程的很多思路都是建立在抽象的基礎上,所以這部分需要仔細的理解體會。
  6. 這裏再提一下接口,從概念上講它是不屬於繼承範疇的,但是Java不支持多繼承,所以通過接口也可以解決部分多繼承的問題。接口中只能出現抽象類,屬性也必須是靜態常量。Java中的接口常用來實現某個功能,以實現對類的規範以及對行爲的封裝。另外接口還有助於對象的行爲安全性,正所謂對人說人話,對鬼說鬼話,下面會有個例子來實現此功能。
  7. 在Java多繼承的工具箱裏,還有一個內部類的概念。
 使用接口來實現俗語“見人說人話,見鬼說鬼話"
  • 新建說人話接口:PersonToneAble
public interface PersonToneAble {
	public abstract void personSpeak();
}

  • 新建說鬼話接口:GhostToneAble
public interface GhostToneAble {
	public abstract void ghostSpeak();
}

  • 實現一個超人類:SuperMan,他既能說人話,也能說鬼話
public class SuperMan implements PersonToneAble, GhostToneAble {

	@Override
	public void ghostSpeak() {
		// TODO Auto-generated method stub
		System.out.println("@#$%*^%");
	}

	@Override
	public void personSpeak() {
		// TODO Auto-generated method stub
		System.out.println("Hello");
	}
}

  • 創建一個機構,僱傭一個超人,分別派他去地球和地獄執行任務
public class Agency {
	
	public void gotoEarth(PersonToneAble p){
		p.personSpeak();
	}
	
	public void gotoEvil(GhostToneAble p){
		p.ghostSpeak();
	}
	
	public void action(){
		SuperMan superMan = new SuperMan();
		gotoEarth(superMan);
		gotoEvil(superMan);
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Agency agency = new Agency();
		agency.action();
	}
}

        上面這個例子用到了接口向上溯型的概念,其實跟子類通過父類僞裝是一樣的道理,通過實現的接口來獲得執行此功能或行爲的對象。

三、多態
        最後再來看一下多態。 多態其實就是通過重載和重寫來實現,它其實就是說在運行時來確定狀態的,上面也已經提到了重載和重寫這兩個概念,這裏略過。

        綜上可以看到,面向對象其實就是這三個概念的組合,而在實際編程實現時將根據不同的命題使用不同的組合方式,這也就是設計模式(後面會寫到)的使用。而對於面向對象容易出現的誤區就是濫用繼承,這部分內容頁是設計模式這門學科的主要研究話題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章