---
# System prepended metadata

title: Java自學紀錄 - 物件導向的程式設計
tags: [類別, Java]

---

###### tags: `Java` `類別`
# Java自學紀錄 - 物件導向的程式設計
## 非程序導向
早期的程式語言,並沒有內儲副程式(程式庫)。當我們開發新的程式時,如果其功能和另一程式很相近,我們就會將那段已完成的程式複製加以利用。久而久之,這些程式很難弄清楚是誰複製誰的,彼此之間也難再共用某些程式碼,當遇到錯誤時或想新增功能時,更是難逐一修改所有程式。
## 程序導向
為了解決以上程式碼公用的問題,各編譯廠商開始提供一些大家常用的函式,比較有規模的公司會將常用的函式集中在一個函式庫中,旗下的軟體產品一律呼叫這些標準的函式庫,而不是從函式庫中複製出來修改,此即為程序導向的程式設計。
## 物件導向
當我們形容自己一個人時,會有以下幾種敘述,它叫做Lucas,身高175,體重67,具有打籃球,跑步的行為。人即為『**物件**』,名稱、身高、體重則稱為『**屬性(Property)**』,而打籃球、跑步則稱為『**行為(Behavior)**』。
既然真實世界是以物件來描述物種,程式設計亦不應侷限在狹隘的方法,而是應以物件的宏觀角度撰寫程式,所以基於物件導向的新觀念,程式開發工具即制定一種新的型別,稱為**類別**。

---
每一個類別都有屬於自己的屬性方法。例如,程式導向的時代,關於開門的函式有**電梯開門**、**汽車開門**、**房子開門**等數種開門的方法,但要如何知道是要哪一種的開門?
撰寫程式時我們會用**電梯.開門**、**汽車.開門**、**房子.開門**(物件與方法間以(.)運算子連結)。
其次,物件導向亦提出了三個觀念,分別是物件的**封裝(Encapsulation)**、**繼承(Inheritance)**、**多型(Polymorphism)**,以解決程序導向的不足。
# 類別與物件的設計
## 類別的設計
```java=
[存取範圍修飾字] class 類別名稱 [extends 繼承類別名稱] [implements 介面名稱]{
    [存取範圍修飾字] 資料型別 資料名稱1(=初始設定);
    [存取範圍修飾字] 資料型別 資料名稱2(=初始設定);
    [存取範圍修飾字] 傳回值資料型別 方法名稱1(參數列)[throws 例為名稱1]
    [存取範圍修飾字] 傳回值資料型別 方法名稱2(參數列)[throws 例為名稱2]
}
```
>以下程式即定義一個類別Pass,共含有兩個``資料成員``score、result及一個``方法成員``dispose()。此類別的功能是判斷成績是否及格,則設定result為**及格**、**不及格**。

```java=
class Pass{
    //資料成員
    int score;
    String result;
    //方法成員
    void dispose(){
        result = "不及格";
        if(score >= 60){
            result = "及格";
        }
    }
}
```
## 類別的變數
完成類別定義後,即可新增一個或數個類別變數,則此類別變數稱為**物件**、**實體**或**實例**。有三步驟,分別是物件的宣告、物件的新增、物件成員的存取。

* 物件宣告
```java=
類別名稱 物件名稱;https:
Pass pa;
```
* 物件新增
```java=
物件名稱 = new 類別名稱();
pa = new Pass();
```
>合併以上兩步驟

```java=
類別名稱 物件名稱 = new 類別名稱();
Pass pa = new Pass();
```
* 成員的存取
```java=
物件名稱.資料名稱;
pa.score;

物件名稱.方法名稱;
pa.dsipose();
```
>**Practice 1** : 寫一程式來判斷成績是否及格

```java=
public class Java_9_2 {
    public static void main(String[] args) {
        Pass pa = new Pass();
        int a = 77;
        pa.score = a;
        pa.dispose();
        String b = pa.result;
        System.out.println(b);
    }
}

class Pass{
    //資料成員
    int score;
    String result;
    //方法成員
    void dispose(){
        result = "不及格";
        if(score >= 60){
            result = "及格";
        }
    }
}
```
>輸出結果
```
及格
```
>**Practice 2** : 設計一個程式計算電費
>A.100度以下,一度以3元計算
>B.100度以上,一度以5元計算
>輸出需繳幾元電費

```java=
import java.util.Scanner;

public class Java_9_2_pratice {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int a;
        a = in.nextInt();
        CountMoney cm = new CountMoney();
        cm.temp = a;
        cm.Count();
        System.out.println(cm.result);
    }
}
class CountMoney{
    int temp;
    int result;
    void Count(){
        if(temp <= 100){
            result = temp * 3;
        }
        else{
            result = temp * 5;
        }
    }
}
```
>輸出結果
```
輸入 : 100
輸出 : 300
輸入 : 500
輸出 : 2500
```
## 建構子(Constructors)
於類別的建置中,他使用的方法較特別,因為建構子的名稱必須和類別名稱相同。
因為於物件建立的同時,此方法亦隨之自動執行,所以此方法通常用於設定資料成員的初始值。
>沿用 **Practice 1**

```java=
public class Java_9_2 {
    public static void main(String[] args) {
        Pass pa = new Pass(); //宣告與新增物件時,即設定 pa.score = 22;
        pa.dispose();
        String b = pa.result;
        System.out.println(b);
    }
}

class Pass{
    //資料成員
    int score;
    String result;
    //建構子
    Pass(){
        score = 77;
    }
    //方法成員
    void dispose(){
        result = "不及格";
        if(score >= 60){
            result = "及格";
        }
    }
}
```
>輸出結果
```
及格
```
### 建構子多載
```java=
Pass(){
    score = 77;
}

Pass(int value){
    score = value;
}

Pass pa = new Pass(); //執行Pass()
Pass pa = new Pass(77); //執行Pass(int)
```
## 解構子(Destructors)
**建構子**相對應的方法稱為**解構子**,它負責歸還建構子所配置的各項資源。但因為Java會負責歸還所有德資料,因此Java就沒有解構子存在的必要。
## 資料封裝
像電視,它用機殼把一些零件開關包裝起來,只留下螢幕跟部分開關讓使用者欣賞節目。軟體程式也是如此,所以對於類別的規劃,我們應重視所有方法,欄位及屬性封裝。
## 存取範圍修飾字
Java提供public、< default >(default表空白)、protected、private等存取修飾字,使成員有不同得封裝等級,以避免程式與類別庫間的干擾。

| 修飾字    | 說明                                             |
|:--------- |:------------------------------------------------ |
| public    | **不同套件**的所有類別皆可存取                   |
| < default > | **同一套件**的所有類別皆可存取                   |
| protected | **同一類別**與其**衍生子**或稱**子類別**才可存取 |
| private   | 僅供**類別內部**可存取                           |

基於資料的安全性,有些資料必須先檢查是否安全與有效,再將其放入,此時就要透過函式的存取,先給予檢查再放入。運用Pass()中的score來做說明。

```java=
public class Java_9_2 {
    public static void main(String[] args) {
        Pass pa = new Pass();
        boolean c = pa.Setscore(-77);
        if(c){ //true時執行
            pa.dispose();
            String b = pa.result;
            System.out.println(b);
        }
    }
}

class Pass{
    private int score;
    public String result;
    public boolean Setscore(int a){
        if(a>=0 & a<=100){
            score = a;
            return true;
        }
        else {
            System.out.println("input error");
            return false;
        }
    }
    void dispose(){
        result = "不及格";
        if(score >= 60){
            result = "及格";
        }
    }
}
```
----
## static
static僅能用於修飾資料與方法成員,也就是說static不能修飾類別。當自料或方法加上static時,我們稱此資料為**類別變數(Class Variables)**,或稱為**公用變數**,而未加static的成員則稱為**實例變數(Instance Variable)** 或是 **實例方法**。

### 實例變數(Instance Variable)
先前我們所使用的都是實例變數,均要宣告新增物件時才能使用,每個物件都分配一個記憶體,所以每個實例變數都是獨立的,彼此間不互相干擾。
### 類別變數(Class Variables)
在資料成員前加static修飾字時,此成員就稱為類別變數。類別變數可以不用宣告新增物件即可使用。例如Math類別中的PI,可直接使用類別名稱機上成員名稱,且中間以 **(.)** 連結。
類別變數宣告新增後,用的都是同一個記憶體,所以更改其中一個的值,++其他的值也會隨之改變++。
>example
```java=
public class Java_9_2_static {
    public static void main(String[] args) {
        Pass1 pa1 = new Pass1();
        Pass1 pa2 = new Pass1();
        Pass2 sta1 = new Pass2();
        Pass2 sta2 = new Pass2();
        
        System.out.println("執行實例變數 : ");
        pa1.score = 10;
        pa2.score = 20;
        System.out.println("pa1.score = "+pa1.score);
        System.out.println("pa2.score = "+pa2.score);
        
        System.out.println("執行類別變數");
        sta1.score = 30;
        System.out.println("sta2.score = "+sta2.score); //40 -> 30
        sta2.score = 40;
        System.out.println("sta1.socre = "+sta1.score); //30 -> 40
    }
}
class Pass1{ //實例變數
    int score;
}
class Pass2{ //類別變數
    static int score;
}
```
----
## 物件陣列
輸入n表示有n筆測資
2~n+1行分別輸入測資
輸出結果(及格或不及格)
```java=
import java.util.Scanner;

public class Java_9_2_array {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n;
        n = in.nextInt();
        Pass pa[] = new Pass[n]; //宣告Pass類別裡面的陣列
        for(int i=0;i<n;i++){
            int tmp = in.nextInt();
            pa[i] = new Pass(tmp);
            boolean c = pa[i].Setscore(tmp);
            if(c) pa[i].dispose(); //true時執行
            else System.out.println("input error");
        }
    }
}
class Pass{
    private int score;
    public String result;
    public Pass(int a){
        if(a>0 & a<=100){
            score = a;
        }
    }
    public boolean Setscore(int a){
        if(a>0 & a<=100){
            a = score;
            return true;
        }
        else{
            return false;
        }
    }
    public void dispose(){
        result = "不及格";
        if(score >= 60){
            result = "及格";
        }
        System.out.println(result);
    }
}
```
>執行結果

![](https://i.imgur.com/MPIkVOn.png)

# 繼承(Inheritance)
任何新產品的開發大多不是無中生有,都是從舊有產品中繼承某些特性,再加入新的零件而成的一項產品。軟體的開發也是如此。
Java使用extends保留字繼承既有的類別。
例如要讓Pass2來繼承Pass類別的寫法
```java=
class Pass2 extends Pass{
}
```
此時,Pass2可繼承Pass類別中的< default >,Public,pretected成員。
上式中的Pass為基礎類別(Base class),Pass2為衍生類別(Derived class)。
* 改寫(Override)
若要改寫方法的話,可以在繼承類別下改寫
```java=
class Pass2 extends Pass {
    // Override dispose
    void dispose() {
        result = "不及格";
        if (score >= 70) { //把上個例題的標準改為70分
            result = "及格";
        }
    }
}
```
### protected
可以繼承該類別的衍生類別。
### final
將成員設為final的話,她就變成個常數,不能被其他衍生類別改寫和繼承。
### super
再衍生類別中,若要呼叫基礎類別的成員,中間以 ***(.)*** 連結。
### this
用於呼叫自己類別的成員,用法跟super相同。
>例題
>運用Cycle類別來算出圓柱底面積
>Cycle2繼承Cycle算出圓柱體體積

```java=
public class Java_Cycle_Cycle2 {
    public static void main(String[] args) {
        Cycle cy1 = new Cycle(5);
        System.out.println("radius = "+cy1.getradius());
        System.out.println("area = "+cy1.getarea());
        Cycle2 cy2 = new Cycle2(cy1.radius,10);
        System.out.println("volume = "+cy2.getvolume());
    }
}
class Cycle{
    int radius;
    Cycle(){
        radius = 2;
    }
    Cycle(int r){
        radius = r;
    }
    int getradius(){ //回傳半徑
        return radius;
    }
    double getarea(){ //回傳底面積
        return radius*radius*Math.PI;
    }
}
class Cycle2 extends Cycle{
    int length;
    Cycle2(int r,int l){
        length = l;
        radius = r;
    }
    double getvolume(){
        return super.getarea()*length; //呼叫基礎類別的方法getarea
    }
}
```
----
# 介面(Interface)
有天你電腦的鍵盤會掉了,要做的就是先查看鍵盤規格,並買一個符合標準的鍵盤回來,不同品牌的鍵盤都會有各自的規格,所以產品可以如此的通用。軟體設計的概念也一樣。
Java中的**interface型別**與**類別**相似,他也有資料與方法成員,但是介面的資料成員,僅可以是常數,方法則是只能定義方法的原型,不能實作。主要是靠繼承此介面的類別來實作。
簡單來說介面就是定義規格,讓其他類別繼承此規格。
## 介面的設計
```java=
interface 介面名稱 [extends 介面名稱]{
    資料成員;
    方法成員;
}
```
## 介面的實作
```java=
class 類別名稱 implements 介面名稱{
    資料成員;
    方法成員(){
        方法實作;
    }
}
```
>例題
>輸入一分數判斷其是否達標
>Collage standard = 60
>Master standard = 70

```java=
import java.util.Scanner;

public class Java_9_4_interface {
    public static void main(String[] args) {
        System.out.print("input score : ");
        Scanner in = new Scanner(System.in);
        int a;
        a = in.nextInt();
        collage pa1 = new collage();
        pa1.score = a;
        pa1.dispose();
        master pa2 = new master();
        pa2.score = a;
        pa2.dispose();
        System.out.println("College result: "+pa1.result); //standard =  60
        System.out.println("Master result: "+pa2.result);  // standard = 70
    }
}
interface Pass{ //介面宣告
    void dispose();
}
class collage implements Pass{
    protected int score;
    protected String result;
    public void dispose(){
        result = "不及格";
        if(score >= 60){
            result = "及格";
        }
    }
}
class master implements Pass{
    protected int score;
    protected String result;
    public void dispose(){
        result = "不及格";
        if(score >= 70){
            result = "及格";
        }
    }
}
```
## 實作多介面
一個類別可以同時實作多個介面,介面間以 **(,)** 隔開。
```java=
class ABC implements A,B,C{ //ABC類別同時擁有A,B,C介面的資料成員及方法。可以同時實作A,B,C中的方法。
}
```
## 多介面繼承
Java的介面可以實現類別的**多重繼承**。
```java=
interface ABC extends A,B,C{ //ABC介面含有A,B,C介面的資料成員及方法。
}
```
----
# 套件(Package)
當我們的類別越來越多時,就必須分類了。Java是使用套件package來做分類,每一個套件都會是一個資料夾。
* step 1 : 先創建一個package

![](https://i.imgur.com/TIUVcZC.png)
* step 2 : 命名為相關名稱

![](https://i.imgur.com/7f2039D.png)
* step 3 : 建立一個類別

![](https://i.imgur.com/cotw2Gp.png)

* step 4 : import 套件

![](https://i.imgur.com/xcw1X5C.png)

==:warning:import中的(.)相當於檔案的路徑(/) !==
