1. 程式人生 > >如何理解Java中的面向物件

如何理解Java中的面向物件

       好幾次面試都問到了這個問題,回答的也都不好,暫且總結一下:
       我的理解是:面向物件是向現實世界模型的自然延伸,這是一種”萬物皆物件”的程式設計思想。在現實生活中的任何物體都可以歸為一類事物,而每一個個體都是一類事物的例項。
       面向物件有三大特性:封裝、繼承、多型。
       (1)封裝。是將一類事物的屬性和行為抽象成一個類,一般是使其屬性私有化,行為公開化,提高了資料的隱祕性的同時,使程式碼模組化。這麼做的好處是:
              • 將變化隔離。
              • 便於使用。
              • 提高程式碼複用性。
              • 提高安全性。
       封裝原則:
              • 將不需要對外提供的內容都隱藏起來。
              • 把屬性都隱藏,提供公共方法對其訪問。
Java中可以通過對類的成員設定一定的訪問許可權,實現類中成員的資訊隱藏。

private:類中限定為private的成員,只能被這個類本身訪問。如果一個類的構造方法宣告為private,則其它類不能生成該類的一個例項。
default:類中不加任何訪問許可權限定的成員屬於預設的(default)訪問狀態,可以被這個類本身和同一個包中的類所訪問。
protected:類中限定為protected的成員,可以被這個類本身、它的子類(包括同一個包中以及不同包中的子類)和同一個包中的所有其他的類訪問。
public:類中限定為public的成員,可以被所有的類訪問。
訪問許可權
       (2)繼承。基於已有的類的定義為基礎,構建新的類,已有的類稱為父類,新構建的類稱為子類,子類能呼叫父類的非private修飾的成員,同時還可以自己新增一些新的成員,擴充父類,甚至重寫父類已有的方法,更其表現符合子類的特徵。
       Java中父類可以擁有多個子類,但是子類只能繼承一個父類,稱為單繼承。
       繼承的好處是:
              • 實現了程式碼的複用。
              • Java中所有的類都是通過直接或間接地繼承java.lang.Object類得到的。
              • 子類不能繼承父類中訪問許可權為private的成員變數和方法。
              • 子類可以重寫父類的方法,即命名與父類同名的成員變數。

       Java中通過super來實現對父類成員的訪問,super用來引用當前物件的父類。super 的使用有三種情況:
              • 訪問父類被隱藏的成員變數,如:super.variable;
              • 呼叫父類中被重寫的方法,如:super.Method([paramlist]),super())呼叫父類構造方法;
              • 呼叫父類的建構函式,如:super([paramlist]);

       super和this的用法相同:this代表本類應用 ;super代表父類引用 。當子父類出現同名成員時,可以用super進行區分 ,子類要呼叫父類建構函式時,可以使用super語句。
       在子類覆蓋方法中,繼續使用被覆蓋的方法可以通過super.函式名獲取。

注意:

       1 . 子類中所有的建構函式預設都會訪問父類中空引數的建構函式,因為每一個建構函式的第一行都有一條預設的語句 super();子類會具備父類中的資料,所以要先明確父類是如何對這些資料初始化的。當父類中沒有空引數的建構函式時,子類的建構函式 必須通過this或者super語句指定要訪問的建構函式。

       2 . 覆蓋時,子類方法許可權一定要大於等於父類方法許可權靜態只能覆蓋靜態。父類中的私有方法不可以被覆蓋。

       3.被final修飾的類是一個最終類,不可以被繼承。
             被final修飾的方法是一個最終方法,不可以被覆蓋。
             被final修飾的變數是一個常量,只能賦值一次。

       4.內部類只能訪問被final修飾的區域性變數。
       (3)多型。方法的重寫、過載與動態連線構成多型性。如果說封裝和繼承是為了使程式碼重用,那麼多型則是為了實現介面重用。多型的一大作用就是為了解耦–為了解除父子類繼承的耦合度。如果說繼承中父子類的關係式IS-A的關係,那麼介面和實現類之之間的關係式HAS-A。簡單來說,多型就是允許父類引用(或介面)指向子類(或實現類)物件。很多的設計模式都是基於面向物件的多型性設計的。
       多型性:傳送訊息給某個物件,讓該物件自行決定響應何種行為。

通過將子類物件引用賦值給超類物件引用變數來實現動態方法呼叫。

  java 的這種機制遵循一個原則:當超類物件引用變數引用子類物件時,被引用物件的型別而不是引用變數的型別決定了呼叫誰的成員方法,但是這個被呼叫的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法。

  1. 如果a是類A的一個引用,那麼,a可以指向類A的一個例項,或者說指向類A的一個子類。

  2. 如果a是介面A的一個引用,那麼,a必須指向實現了介面A的一個類的例項。要理解多型性,首先要知道什麼是“向上轉型”。
  
子類Cat繼承了Animal類,那麼後者就是前者是父類。

  Cat c = new Cat();//例項化一個Cat的物件,

  Animal a = new Cat();//定義了一個Animal型別的引用,指向新建的Cat型別的物件
  由於Cat是繼承自它的父類Animal,所以Animal型別的引用是可以指向Cat型別的物件的。那麼這樣做的什麼意義是:因為子類是對父類的一個改進和擴充,所以一般子類在功能上較父類更強大,屬性較父類更獨特,
  定義一個父類型別的引用指向一個子類的物件既可以使用子類強大的功能,又可以抽取父類的共性。
  所以,父類型別的引用可以呼叫父類中定義的所有屬性和方法,但是對於子類中定義而父類中沒有的方法,它是無可奈何的;
  同時,父類中的一個方法只有在在父類中定義而在子類中沒有重寫的情況下,才可以被父類型別的引用呼叫;
  對於父類中定義的方法,如果子類中重寫了該方法,那麼父類型別的引用將會呼叫子類中的這個方法,這就是動態連線。
  實現多型,有二種方式,覆蓋(override),過載(overload)。

       覆蓋,是指子類重新定義父類的虛擬函式的做法。它是覆蓋了一個方法並且對其重寫,以求達到不同的作用。在覆蓋要注意以下的幾點:
              1、覆蓋的方法的標誌必須要和被覆蓋的方法的標誌完全匹配,才能達到覆蓋的效果;
              2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;
              3、覆蓋的方法所丟擲的異常必須和被覆蓋方法的所丟擲的異常一致,或者是其子類;
              4、被覆蓋的方法不能為private,否則在其子類中只是新定義了一個方法,並沒有對其進行覆蓋。

       過載,是指允許存在多個同名函式,而這些函式的引數表不同(或許引數個數不同,或許引數型別不同,或許兩者都不同)。它是指我們可以定義一些名稱相同的方法,通過定義不同的輸入引數來區分這些方法,然後再呼叫時,在使用過載要注意以下的幾點:
              1、在使用過載時只能通過不同的引數樣式。例如,不同的引數型別,不同的引數個數,不同的引數順序(當然,同一方法內的幾個引數型別必須不一樣,例如可以是fun(int,float),但是不能為fun(int,int));
              2、不能通過訪問許可權、返回型別、丟擲的異常進行過載;
              3、方法的異常型別和數目不會對過載造成影響;
              4、對於繼承來說,如果某一方法在父類中是訪問許可權是priavte,那麼就不能在子類對其進行過載,如果定義的話,也只是定義了一個新方法,而不會達到過載的效果。

       多型也有弊端:當父類引用指向子類物件時,雖然提高了擴充套件性,但是隻能訪問父類中具備的方法,不可以訪問子類中特有的方法。(前期不能使用後期產生的功能,即訪問的侷限性)
       參考文章:
              對於面向物件的簡單理解
              面試總結之談談你對面向物件的理解
              面試——你是如何理解java的面向物件思想