天天看點

面向對象基礎學習心得

一、類與對象

類是用來對一組具有相同特性事物的描述,而對象就是類的執行個體,類用來描述對象,就像一座大樓與樓的設計圖的關系,蓋成一座大樓需要一張設計圖來确定這座樓有多高,有多大,一層有幾個房間等。萬物皆對象。

例如:

//一個描述人的類
public class Person {
    private String name;  //人的姓名
    private int age;     //人的年齡
    private String sex ;   //人的性别
    public void spaek() {
        System.out.println("說話");
    }
}
           

上面的代碼,是一個關于人的類, 類中描述了一個人的屬性如姓名,年齡;還有人的一個動作說話,可以說,通過這個類,我們就能簡單的得到一個‘人’。

Person people1  = new Person(); //java中通過new關鍵字可以建立一個對象。
people1.speak(); // 通過對象可以調用該對象的speak方法。
           

建立一個對象後就可以調用其中的成員變量和方法,要注意成員變量的修飾符,public(在所有的類中都能通路),private(隻能在自身類中通路,也不能在子類中通路),protected(隻能被自身類,子類和同一包中的類通路),一般常用的就這三個。在上述代碼中,調用了speak方法,其修飾符public,說明可以任意類中的通路,而name,age屬性,都是私有的private,隻能在本類中通路,如果需要通路,我們可以在Person類設定return方法來傳回,這樣可以保護類中的資料,起到封裝的特性,如:

public String getName(){
    return this.name;
}
           

二、構造方法

構造方法就是對對象的初始化,就是在new對象時,使對象當出現時就自帶有一些屬性值,比如說一個人,剛出生是父母一般都會起好名字,那麼我們為什麼不在建立對象時就給對像的名字指派呢?這就需要構造方法。

public class Person {
    private String name;
    protected int age;
    //構造方法,需要傳入名字。
    public Person(String name) {
        this.name = name;
    }

    public void spaek() {
            System.out.println("說話");
    }

    public String getName(){
        return this.name;
    }
}
           

構造方法是與類同名,公共的,沒有傳回值的方法,不用使用者調用,會在建立對象是自動調用。

Person people1 = new Person("小王");
people1.getName(); //調用people1的getName方法得到name的值  此時name的值同過構造方法的指派,為“小王”。
           

三、 重構

上面我們講解了構造方法,那麼問題來了,如果一個人一出生還沒有起好名字,那怎麼辦呢?這就需要說到方法的重構了。就是方法名稱一樣,傳回值一樣,就是方法的傳參不一樣。建立對象是根據傳入參數的個數。類型的不同,來調用不同的構造方法。不止是構造方法,成員方法也能重構(注意:重構時的參數要麼要在個數上不同,要麼要在傳入參數的類型上不同)。

public class Person {
    private String name;
    protected int age;
    public Person() {   //沒有參數的構造方法
        this.name = "無名";
    }
    public Person(String name) {
        this.name = name;
    }

    public void spaek() {
        System.out.println("說話");
    }
    public String getName(){
        return this.name;
    }
}
           

當我們調用時,可以傳入不同的參數來建立對象。

Person people1 = new Person("小王");  //建立一個名字為小王的人,調用有參構造方法。
        Person people2 = new Person();   //建立一個沒有名稱的人,調用無參構造方法
        System.out.println(people1.getName()); // 輸出為  小王
        System.out.println(people2.getName()  //輸出為  無名
           

四、封裝

封裝、繼承、多态是面向對象的三大特性,現在我們來說封裝, 封裝就是每個對象都包含他能進行操作所需要的所有資訊,把這些資訊包裝在類中,這樣就實作了封裝。

封裝有很多好處,第一、良好的封裝能夠減少耦合,第二、類内部的實作可以自由的修改。

類的封裝就好比一座房子,裡面擺放了精美的家具,如果沒有圍牆,那房子内的物品任何人都可以看或者改動,由于有了圍牆(封裝),房屋内的物品就不會被外人動了,但是如果沒有門窗,那麼房子就成了一個鐵盒子,就算裡面的東西再怎麼豪華,再怎麼精美,人不能住進去,也沒用。是以要有門窗,使主人能夠住進來。就像剛才的那個Person類,其中的name屬性是私有的,不能夠在類外通路,我們加了個getName()方法,是我們能夠通路到name 的值,這就是封裝對象暴露在外的屬性和方法。

五、繼承

繼承就是子類繼承父類 ,會繼承父類的非private的成員變量和成員方法,子類也能擁有屬于自及的成員變量和成員方法,并且能夠重寫父類的成員方法。

例如:人是一種總稱,但是人有分為中國人,美國人,德國人等,各個不同國家的人擁有相同的屬性,如姓名,性别,年齡等,那麼我們可以使各個國家人的類繼承人的類,人類中包括姓名、性别、年齡等一些共有屬性。而各個國家的人類中可以有一些輸入自己的一些行屬性等。

class Person {
    public String name;
    public int age;

    public Person() {
        this.name = "無名";
    }

    public Person(String name) {
        this.name = name;
    }

    public void spaek() {
        System.out.println("說話");
    }

    public void run () {
        System.out.println("跑");
    }
}
//繼承父類
class Chinese extends Person {
    //構造方法,super()調用父類的方法
    public Chinese(String name) {
        super(name);
    }
    //子類特有的方法,中國人唱豫劇
    public void sing() {
        System.out.println("豫劇");
    }

}
           

在上述代碼中,有Chinese子類繼承了Person父類,(需要說明的是,在子類中的構造方法,如果父類中有構造方法的重構,而父類中沒有無參數的構造方法的聲明,那麼在子類中的構造方法必須指定調用那個父類的構造方法,否則,将會出錯。)會擁有父類的所有成員和方法,而在子類中則增加類中國人特有的平劇。如果我們在main函數中new出Chinese的對象,那麼是可以調用父類的成員屬性和方法的。

如果之後我們想加入美國人、德國人等,隻需要建立相應的類,然後繼承Person類,同樣可以擁有name,age等屬性,以此,提高了代碼的可讀性、和複用性。

使用繼承是需要注意的是,兩事物A和B之間的關系必須是A包含B,那麼才能讓B繼承A。

六、多态

現在假設要舉行一場跑步運動會。各個國家的熱都要參加,要怎樣才能讓不同國家的人同時賽跑呢,那麼這就用到了多态,多态就是不同的對像可以執行相同的動作,就拿豫劇來說吧,有一位非常出名的老父親,演豫劇演的特别好,他兒子每天跟老父親學習,也學是非常像,有一天,老父親生病了,上不了台表演,他兒子可以替父親上台表演,因為他們表演的特别像,再因為在台上化了妝,觀衆根本認不出來。這就是多态的原理,聲明對像是聲明父類對象,new對象時new出子類對象。

class Person {
    public String name;
    public int age;
    public Person() {
        this.name = "無名";
    }
    public Person(String name) {
        this.name = name;
    }

    public void spaek() {
        System.out.println("說話");
    }

    public void run () {
        System.out.println("跑");
    }
}

class Chinese extends Person {
    public Chinese(String name) {
        super(name);
    }

    public void run(){
        System.out.println("我是中國人"+this.name+",我參加運動會");
    }

    public void sing() {
        System.out.println("豫劇");
    }
}

public class RunSport {
    public static void main(String[] args) {
        Person chinese = new Chinese("小王"); //用父類指向子類對象。
        chinese.run(); // 調用子類中重寫後的run方法 ,輸出 "我是中國人小王,我參加運動會"
    }
}
           

使用多态時要注意 1.子類以父類的身份出現,2. 子類的工作方式以自己的工作方式實作;3. 子類以父類的身份出現時,子類特有的屬性和方法不可以使用(子類中重寫父類的方法可以使用);

下面,我們來運用多态來實作運動會。我們先來增加幾個國家:

//美國人
class American extends Person {
    public American(String name) {
        super(name);
    }

    public void run(){
        System.out.println("我是美國人"+this.name+",我參加運動會");
    }

}

//德國人
class  German extends Person {
    public  German(String name) {
        super(name);
    }

    public void run(){
        System.out.println("我是德國人"+this.name+",我參加運動會");
    }

}

俄羅斯人
class Russians extends Person {
    public Russians(String name) {
        super(name);
    }

    public void run(){
        System.out.println("我是俄羅斯人"+this.name+",我參加運動會");
    }

}
           

我們用Java中的容器來存儲參賽人員,來實作比賽。

public class RunSport {
    public static void main(String[] args) {
        ArrayList<Person> athletes = new ArrayList<Person>();
        athletes.add (new Chinese("小王"));
        athletes.add (new American("邁克"));
        athletes.add (new German("約翰"));
        athletes.add (new Russians("鮑裡斯"));

        for (int i = ; i < athletes.size(); i++) {
            athletes.get(i).run();
        }
    }
}
/* 運作結果
我是中國人小王,我參加運動會
我是美國人邁克,我參加運動會
我是德國人約翰,我參加運動會
我是俄羅斯人鮑裡斯,我參加運動會
*/ 
           

這就是不同的對象可以執行相同的動作,但要通過他們自己的代碼實作來執行。

七、抽象類

在上述代發中我們可以發現Person類根本不用執行個體化,那麼我們就可以把他設為抽象類,抽象類是不能執行個體化的。把需要重寫的方法設定為抽象方法。

abstract class Person {
    public String name;
    public int age;
    public Person() {
        this.name = "無名";
    }
    public Person(String name) {
        this.name = name;
    }

    //普通方法,可以被繼承,也可被重寫
    public void spaek() {
        System.out.println("說話");
    }
    //抽象方法,在子類中必須重寫
    public abstract void run ();
}

class Chinese extends Person {
    public Chinese(String name) {
        super(name);
    }

    //重寫父類的抽象方法,以自己的方式實作
    public void run(){
        System.out.println("我是中國人"+this.name+",我參加運動會");
    }

}
           

抽象方法在使用時應該注意:

  1. 抽象類不能執行個體化
  2. 抽象方法是必須被子類重寫的方法
  3. 如果父類中擁有抽象方法,那麼父類必須被聲明稱抽象類

八、接口

根據上述例子,當一個國家或幾個國家的人擁有特别的功能時怎麼辦呢,有人會說再各自國家的子類中定義各自特殊的方法,但是那樣的話會使代碼變得雜亂,使用接口是讓使用者和其他開發人員更容易了解他人的代碼。

接下來我們以我們的國球為例,假設一個人會打乒乓球,那麼我們先要有一個打乒乓球的接口,聲明接口是需要注意,接口中不允許出現任何成員的執行方式,不能聲明無值得成員變量,若定義成員變量是賦初值,那麼這個成員變量會預設聲明為public static final 類型。

interface  PingPong{
    //聲明打乒乓球方法
    public void play();
}
           

那麼在子類中就需要實作該方法

class Chinese extends Person implements PingPong{
    public Chinese(String name) {
        super(name);
    }

    public void run(){
        System.out.println("我是中國人"+this.name+",我參加運動會");
    }

    public void sing() {
        System.out.println("豫劇");
    }

    //實作接口中方法
    public void play() {
        System.out.println("打乒乓球");
    }
}
           

有了這個接口,當在出先一個人會打乒乓球時,我們直接讓這個人繼承PingPong類就行了。

現在來說一下接口和抽象類的差別,抽象類可以給出一些成員變量的實作,而接口不能包含有實作,抽象類的抽象成員可被子類部分實作,接口的成員需要需要實作類完全實作。

參考文獻《大話設計模式》程傑著