1. 程式人生 > >1.面向物件程式設計思想(封裝繼承多型介面)

1.面向物件程式設計思想(封裝繼承多型介面)

封裝:

1.定義:隱藏物件的屬性和實現細節,僅對外公開介面,控制在程式中屬性的讀和修改的訪問級別。

2.封裝的目的是:增強安全性和簡化程式設計,使用者不必瞭解具體的實現細節,而只是要通過外部介面,一特定的訪問許可權來使用類的成員。

3.封裝的基本要求是:把所有的屬性私有化,對每個屬性提供getter和setter方法,如果有一個帶參的建構函式的話,那一定要寫一個不帶參的建構函式。在開發的時候經常要對已經編寫的類進行測試,所以在有的時候還有重寫toString方法,但這不是必須的。

繼承:

1.目的:實現程式碼的複用。

2.介紹:當兩個類具有相同的特徵(屬性)和行為(方法)時,可以將相同的部分抽取出來放到一個類中作為父類,其它兩個類繼承這個父類。繼承後子類自動擁有了父類的屬性和方法,但特別注意的是,父類的私有屬性和構造方法並不能被繼承。另外子類可以寫自己特有的屬性和方法,目的是實現功能的擴充套件,子類也可以複寫父類的方法即方法的重寫。子類不能繼承父類中訪問許可權為private的成員變數和方法。子類可以重寫父類的方法,及命名與父類同名的成員變數。有時候我們需要這樣的需求:我們需要將某些事物儘可能地對這個世界隱藏,但是仍然允許子類的成員來訪問它們。這個時候就需要使用到protected



多型:

1.概念:相同的事物,呼叫其相同的方法,引數也相同時,但表現的行為卻不同。

2. Java實現多型有三個必要條件:繼承、重寫、向上轉型。

         繼承:在多型中必須存在有繼承關係的子類和父類。

         重寫:子類對父類中某些方法進行重新定義,在呼叫這些方法時就會呼叫子類的方法。

         向上轉型:在多型中需要將子類的引用賦給父類物件,只有這樣該引用才能夠具備技能呼叫父類的方法和子類的方法。

      只有滿足了上述三個條件,我們才能夠在同一個繼承結構中使用統一的邏輯實現程式碼處理不同的物件,從而達到執行不同的行為。

3.多型的實現方式:

(1)基於繼承實現的多型

      基於繼承的實現機制主要表現在父類和繼承該父類的一個或多個子類對某些方法的重寫,多個子類對同一方法的重寫可以表現出不同的行為。

(2)基於介面實現的多型

      繼承是通過重寫父類的同一方法的幾個不同子類來體現的,那麼就可就是通過實現介面並覆蓋介面中同一方法的幾不同的類體現的。

      在介面的多型中,指向介面的引用必須是指定這實現了該介面的一個類的例項程式,在執行時,根據物件引用的實際型別來執行對應的方法。

      繼承都是單繼承,只能為一組相關的類提供一致的服務介面。但是介面可以是多繼承多實現,它能夠利用一組相關或者不相關的介面進行組合與擴充,能夠對外提供一致的服務介面。所以它相對於繼承來說有更好的靈活性。

4.多型性主要表現在如下兩個方面:

(1)方法過載.通常指在同一個類中,相同的方法名對應著不同的方法實現,但是方法的引數不同. (2)成員覆蓋.通常指在不同類(父類和子類)中,允許有相同的變數名,但是資料型別不同;也允許有相同的方法名,但是對應的方法實現不同.

5.多型的好處:程式的可擴充套件性及可維護性增強。

抽象:

1.介紹:在面向物件的概念中,我們知道所有的物件都是通過類來描繪的,但是並不是所有的類都是用來描繪物件的,如果一個類中沒有包含足夠的資訊來描繪一個具體的物件,這樣的類就是抽象類。抽象類往往用來表徵我們在對問題領域進行分析、 設計中得出的抽象概念,是對一系列看上去不同,但是本質上相同的具體概念的抽象,我們不能把它們例項化(拿不出一個具體的東西)所以稱之為抽象

  比如:我們要描述“水果”,它就是一個抽象,它有質量、體積等一些共性(水果有質量),但又缺乏特性(蘋果、橘子都是水果,它們有自己的特性),我們拿不出唯一一種能代表水果的東西(因為蘋果、橘子都不能代表水果),可用抽象類來描述它,所以抽象類是不能夠例項化的。當我們用某個類來具體描述“蘋果”時,這個類就可以繼承描述“水果”的抽象類,我們都知道“蘋果”是一種“水果”。

2.抽象方法:被abstract修飾的方法是抽象方法,抽象方法沒有方法體。修飾符 abstract 返回值型別 函式名();抽象方法的修飾符只能用public或者protected或者沒有修飾,不能被final,static,private修飾

(1)、類即使不包含抽象方法,也可以定義成抽象類。
(2)、類中含有抽象方法的類一定要定義成抽象類。
(3)、抽象類中欄位的定義和子類的訪問與一般類沒有變化。
(4)、擴充套件抽象類有兩種方法,第一種是在子類中定義部分抽象方法或者抽象方法不定義,這樣子類也必須定義成抽象類,第二種是定義全部的抽象方法,這樣子類就可以不定義成抽象的了。
(5)、抽象類不能被例項化,但是可以定義一個抽象類的物件變數,這個變數可以引用非抽象子類的物件。
(6)、抽象類中包含有構造方法,也可以顯式書寫構造方法,構造方法在例項化子類的物件中呼叫。


介面與抽象類的區別:

不同點:
1、介面可以多實現,而抽象類只能單繼承
2、抽象類可以有非抽象的方法和構造方法、變數,但是介面只能有抽象方法,靜態常量。
3、抽象類和子類具有父子關係,子類能擁有父類中一些屬性。介面雖然某個類實現一個介面,但是由於介面中的變數都為靜態常量,不存在繼承關係。


相同點:
1、無論介面還是抽象類,都無法直接例項化,其自身例項化需要靠實現類或子類來實現。
2、介面和抽象類都必須實現其中的所有方法

抽象類(abstract class)的定義方式如下: 

public abstract class AbstractClass             //裡面至少有一個抽象方法
{
   public int t;  //普通資料成員
   public abstract void method1();   //抽象方法,抽象類的子類在類中必須實現抽象類中的抽象方法
   public abstract void method2(); 
   public void method3();   //非抽象方法
   public int method4();
   publi int method4 (){
        …… //抽象類中可以賦予非抽象方法方法的預設行為,即方法的具體實現
   }

       public void method3(){
        …… //抽象類中可以賦予非抽象方法方法的預設行為,即方法的具體實現
   } 

}

介面(interface)的定義方式如下: 

public interface Interface

   static final int i;  //介面中不能有普通資料成員,只能夠有靜態的不能被修改的資料成員,static表示全域性,final表示不可修改,可以不用static final 修飾,會隱式的宣告為static和final
   

   public void method1();  //介面中的方法一定是抽象方法,所以不用abstract修飾
   

   public void method2();  //介面中不能賦予方法的預設行為,即不能有方法的具體實現
}

1、一個介面可以被多個類實現,一個類也可以實現多個介面。
2、介面中所有的定義的欄位預設都是public static final 的屬性,寫和不寫沒有區別。
3、介面中的方法都是抽象的方法,並且抽象的方法預設都是public abstract修飾的,不能用其他的修飾符修飾,可以不寫。
4、介面中沒有構造方法
5、介面不是類,尤其不能使用new運算子例項化一個介面。但是可以宣告介面的變數,這個變數可以指向實現了此介面的子類。

簡言之抽象類是一種功能不全的類,介面只是一個抽象方法宣告和靜態不能被修改的資料的集合,兩者都不能被例項化。


  從某種意義上說,介面是一種特殊形式的抽象類,在java語言中抽象類表示的是一種繼承關係,一個類只能繼承繼承一個抽象類,而一個類卻可以實現多個介面。在許多情況下,介面確實可以代替抽象類,如果你不需要刻意表達屬性上的繼承的話。

 super的用法:

1.     子類的建構函式如果要引用super的話,必須把super放在函式的首位.

class Base {

    Base() {

       System.out.println("Base");

    }

}

public class Checket extends Base {

    Checket() {

       super();//呼叫父類的構造方法,一定要放在方法的首個語句

       System.out.println("Checket");

    }

    public static void main(String argv[]) {

       Checket c = new Checket();

    }

}

          如果想用super繼承父類構造的方法,但是沒有放在第一行的話,那麼在super之前的語句,肯定是為了滿足自己想要完成某些行為的語句,但是又用了super繼承父類的構造方法。那麼以前所做的修改就都回到以前了,就是說又成了父類的構造方法了。

2.       在java中,有時還會遇到子類中的成員變數或方法與超類(有時也稱父類)中的成員變數或方法同名。因為子類中的成員變數或方法名優先順序高,所以子類中的同名成員變數或方法就隱藏了超類的成員變數或方法,但是我們如果想要使用超類中的這個成員變數或方法,就需要用到super.

 class Country {

    String name;

    void value() {

       name = "China";

    }

}

class City extends Country {

    String name;

    void value() {

    name = "Hefei";

    super.value();//不呼叫此方法時,super.name返回的是父類的成員變數的值null

       System.out.println(name);

       System.out.println(super.name);

    }

    public static void main(String[] args) {

       City c=new City();

       c.value();

       }

}

         為了在子類中引用父類中的成員變數name和方法value(),在程式碼中使用了super、super.name和super.value(),若不呼叫super.value()時,super.name返回父類成員變數預設值null,呼叫此方法時,super.value()方法把成員變數name賦值為China,再利用super.name呼叫父類的成員變數的值。

     另外,要注意的是super.name呼叫的是成員變數的值,

class Country {

    String name="xianfan";

    String value(String name) {

       name = "China";

       return name;

    }

}

class City extends Country {

    String name;

    String value(String name) {

    name = "Hefei";

super.value("失敗");//不呼叫此方法時,super.name返回的是父類的成員變數的值null

       System.out.println(name);

       System.out.println(super.name);

       return name;

    }

    public static void main(String[] args) {

       City c=new City();

       c.value("成功");

    }

}

    結果為:Hefei

xianfan

     此時,super.name返回的值是父類成員變數的值xianfan,而此時的super.value()方法是不起作用的。

3.用super直接傳遞引數:

  class Person {

    public static void prt(String s) {

       System.out.println(s);

    }

    Person() {

       prt("A Person.");

    }

    Person(String name) {

       prt("A person name is:" + name);

    }

}

public class Chinese extends Person {

    Chinese() {

       super(); // 呼叫父類建構函式(1)

       prt("A chinese.");// (4)

    }

    Chinese(String name) {

       super(name);// 呼叫父類具有相同形參的建構函式(2)

       prt("his name is:" + name);

    }

    Chinese(String name, int age) {

       this(name);// 呼叫當前具有相同形參的建構函式(3)

       prt("his age is:" + age);

    }

    public static void main(String[] args) {

       Chinese cn = new Chinese();

       cn = new Chinese("kevin");

       cn = new Chinese("kevin", 22);

    }

}

      結果為:A Person.

A chinese.

A person name is:kevin

his name is:kevin

A person name is:kevin

his name is:kevin

his age is:22

          在這段程式中,this和super不再是像以前那樣用“.”連線一個方法或成員,而是直接在其後跟上適當的引數,因此它的意義也就有了變化。super後加引數的是用來呼叫父類中具有相同形式的建構函式,如1和2處。this後加引數則呼叫的是當前具有相同引數的建構函式,如3處。當然,在Chinese的各個過載建構函式中,this和super在一般方法中的各種用法也仍可使用,比如4處,你可以將它替換為“this.prt”(因為它繼承了父類中的那個方法)或者是“super.prt”(因為它是父類中的方法且可被子類訪問),它照樣可以正確執行。但這樣似乎就有點畫蛇添足的味道了。

this的用法:“this是指向物件本身的一個指標”

說明在什麼情況下需要用到this


        第一、通過this呼叫另一個構造方法,用發是this(引數列表),這個僅僅在類的構造方法中,別的地方不能這麼用。


        第二、函式引數或者函式中的區域性變數和成員變數同名的情況下,成員變數被遮蔽,此時要訪問成員變數則需要用“this.成員變數名”的方式來引用成員變數。當然,在沒有同名的情況下,可以直接用成員變數的名字,而不用this

        第三、在函式中,需要引用該函所屬類的當前物件時候,直接用this。

super和this的異同:

       1)super(引數):呼叫基類中的某一個建構函式(應該為建構函式中的第一條語句) 

       2)this(引數):呼叫本類中另一種形成的建構函式(應該為建構函式中的第一條語句)
       3)super: 它引用當前物件的直接父類中的成員(用來訪問直接父類中被隱藏的父類中成員資料或函式,基類與派生類中有相同成員定義時如:super.變數名    super.成員函資料名(實參)

      4)this:它代表當前物件名(在程式中易產生二義性之處,應使用this來指明當前物件;如果函式的形參與類中的成員資料同名,這時需用this來指明成員變數名)

      5)呼叫super()必須寫在子類構造方法的第一行,否則編譯不通過。每個子類構造方法的第一條語句,都是隱含地呼叫super(),如果父類沒有這種形式的建構函式,那麼在編譯的時候就會報錯。

      6)super()和this()類似,區別是,super()從子類中呼叫父類的構造方法,this()在同一類內呼叫其它方法。

   7)super()和this()均需放在構造方法內第一行。

   8)儘管可以用this呼叫一個構造器,但卻不能呼叫兩個。

   9)this和super不能同時出現在一個建構函式裡面,因為this必然會呼叫其它的建構函式,其它的建構函式必然也會有super語句的存在,所以在同一個建構函式裡面有相同的語句,就失去了語句的意義,編譯器也不會通過。

 10)this()和super()都指的是物件,所以,均不可以在static環境中使用。包括:static變數,static方法,static語句塊。

 11)從本質上講,this是一個指向本物件的指標, 然而super是一個Java關鍵字。

以下是關於子類父類的構造方法的注意事項:


   轉載自http://blog.csdn.net/qq_22118507/article/details/51422591