Nova的科學反主流學院 

反主流的精神在於不屈於大環境, 本站旨在提供輕鬆自學各種科學。

Java 教學-物件導向概念

f:id:immortalnova:20160506160658p:plain

 

前言

我們學程式的時候有時候會聽到物件導向,到底什麼是物件導向,又有什麼好處呢?

物件導向其實就是希望讓程式對應現實的物件,

方便開發維護所設計的功能,包含封裝、繼承、多形

 

1.封裝

首先,就像我們開車子不需要知道車子引擎是怎麼運轉的,只要知道怎麼發動和操作就好。所以我們也希望把程式當成一個黑箱子一樣,只提供給我們使用者應該要知道的東西就好。

舉例來說,以下的TestCar程式會產生一個車子的物件並印出他的最高時速:

 

public class TestCar {
    public static void main(String[] args) {
        Car car1 = new Car(1);
        
        System.out.println("這輛車子的最高時速是:");
        
        System.out.println(car1.getMaxSpeed());
    }
}

class Car
{
    // 車子編號
    private int number;

    public Car(int number){
        this.number = number;
    }

    // 取得車子型號
    public int getMaxSpeed() {
        return number * 20 + 10;
    }
}

 

而在一開始使用Car car1 建造一個Car的物件空間,我們可以把他當成停車格,而這個停車格的名字叫做car1。

不過裡面還沒有停車,所以必須透過new Car產生一台車,然後用 = 符號把他丟到這個停車格內,而Car 後面的括號裡的數字,就是我們可以傳進的參數。

Car car1 = new Car(1);

 

為什麼我們可以傳入參數?因為我們在底下的class Car中定義了預設的產生物件方法

public Car(int number){
    this.number = number;
}

所以他會把傳進來的數字,存到 number 裡面。

(有 this 代表物件裡面的 number, 沒 this 的代表物件外面的 number)

 

 // 車子編號
    private int number;

前面加上private,代表無法直接存取,目的是讓使用者不要直接碰,

因為我們現在是開發車子的人,只希望使用者能開車,而不希望他們自己隨便碰引擎,所以我們把不想讓別人存取到的部分都封裝起來。

 

在這裡,因為已經被我們封裝了,所以我們必須做一個控制器讓使用者取得他們要的東西,在這裡我們寫了一個 getMaxSpeed 方法,能取得車子的最大時速,並且前面加上 public ,表示這個方法是公開的,大家都能用!

 // 取得車子型號
public int getMaxSpeed() {
    return number * 20 + 11;
}

上面回傳的型號剛好是編號的20倍再加上10,這個是我們開發者自己寫的,使用者不知道也不需要知道這一點,他們只想知道這輛車最快時速開多少,不需要知道是編號多少的車影響這一點。

 

透過設計不同變數當物件的屬性,不同的方法當物件的功能或動作,再透過 private 蓋起來,整理好之後前面加上 public 就可以讓使用者使用。

 

日常生活中的例子:

夾娃娃機不能直接拿裡面的東西,我們只能透過外面的操縱桿去控制。

 

 

2.繼承

 

繼承的用意就是為了有邏輯性的重複利用而設計的功能,

可以以剛才的車子例子修改一下,再做個說明:


public class TestCar {
    public static void main(String[] args) {
        Car car = new SportsCar(1);
        
        System.out.println("跑車最大時速是:");
        
        System.out.println(car.getMaxSpeed());
    }
}

class SportsCar extends Car{

    public SportsCar(int number) {
        super(number);
    }
    
    // 取得車子速度
    public int getMaxSpeed() {
        return number * 30 + 20;
    }
}


class Car
{
    // 車子編號
    protected int number;

    public Car(int number){
        this.number = number;
    }
    
    // 取得車子編號
    public int getNumber() {
        return number;
    }

    // 設定車子編號
    public void setNumber(int number) {
        this.number = number;
    }

    // 取得車子速度
    public int getMaxSpeed() {
        return number * 20 + 10;
    }
}

 

首先我們希望製造一台跑車,因為我們已經有 Car (一般車子)了,我們可以直接繼承他

並且修改我們希望不一樣的地方就好:

class SportsCar extends Car{

    public SportsCar(int number) {
        super(number);
    }
    
    // 取得車子速度
    public int getSpeed() {
        return number * 30 + 20;
    }
}

 

使用 extends 關鍵字,就是可以把 Car 有的部分再複製一份過來,所以大部分都不用寫了,除了兩個要寫,一個是我們的跑車建造工具名稱要改一下:

public SportsCar(int number) {
    super(number);
}

 

另一個是我們希望跑車速度比一般車快,所以速度的方法也要改:

// 取得車子速度
public int getSpeed() {
    return number * 30 + 20;
}

 

另外,因為繼承後,有部分相同的變數會用到(如number),所以必須改一下剛才的private:

class Car
{
    // 車子編號
    protected int number;

private改成protected的用意,是讓繼承的物件也能讀取到,所以跑車也可以利用車子的編號產生最高速度了!

 

所以最後,前面停車格一樣固定,後面的new Car要改跑車的名字,其他都可以不用變

(能停所有車子的停車格,就能停跑車,但是能停跑車的停車格,不一定能停所有車子)

Car car = new SportsCar(1);
        
System.out.println("跑車最大時速是:");
        
System.out.println(car.getSpeed());

 

其他日常生活的例子

貓和狗都是動物,可以繼承動物,就可以少寫共通的部分

 

 

3.多形

 

簡單來講,多形就是希望我告訴所有物件做一件事情,但是大家會根據自己的身分去找事情做,如同老板說,今天要好好工作,但是每個人應該是做自己份內的事情,而不是亂做別人的事。

 

再用剛才的例子舉例:

public class TestCar {
    public static void main(String[] args) {
        
        
        Car car1 = new SportsCar(1);
        System.out.println("跑車最大時速是:");
        System.out.println(car1.getMaxSpeed());
        
        Car car2 = new Bus(1);
        System.out.println("公車最大時速是:");
        System.out.println(car2.getMaxSpeed());
    }
}

class SportsCar extends Car{

    public SportsCar(int number) {
        super(number);
    }
    
    // 取得車子速度
    public int getMaxSpeed() {
        return number * 30 + 20;
    }
}

class Bus extends Car{

    public Bus(int number) {
        super(number);
    }
    
    // 取得車子速度
    public int getMaxSpeed() {
        return number * 10 + 10;
    }
}

 

今天公車和跑車都停到我們特製的停車場內,然後偵測最高速度,

這個偵測器會根據車子的種類,自動回傳正確的計算方式:

 

我們會發現下面兩個左邊都是 Car ,代表他們都停到一樣的停車場,只是格子不同。

Car car1 = new SportsCar(1);

Car car2 = new Bus(1);

 

這兩行也都是呼叫相同的方法,不過結果卻會回傳不同的數字。

System.out.println(car1.getMaxSpeed());
System.out.println(car2.getMaxSpeed());

 

主要就是因為兩種車子裡面的取得最大速度方法不同:

// 取得車子速度
    public int getMaxSpeed() {
        return number * 30 + 20;
    }

// 取得車子速度
    public int getMaxSpeed() {
        return number * 10 + 10;
    }

 

這樣子的好處是,當有更多的車子和更多種車子的時候,我們還可以把他丟到一個陣列,用迴圈跑一遍,他就會全部很適合的處理完,不用再一行一行分開寫。

 

根據物件的型態,呼叫不同的方法,就稱為多形

 

日常生活中的例子

動物一樣都有叫這個動作,但是叫聲不同