---
# System prepended metadata

title: Java--類別與物件
tags: [Java]

---

---
tags: Java
---
# Java--類別與物件
>參考資料：
>* http://www.codedata.com.tw/book/java-basic-source/ch11-1.htm
>* https://caterpillar.gitbooks.io/javase6tutorial/content/c7_1.html
>* https://noob.tw/java-oop/
>* http://pclevin.blogspot.com/2013/02/java-java-return.html
## 定義類別 (class)
### 以物件思考問題
* 物件導向的思維：以物件為中心來思考問題
1. 識別出問題中的物件
2. 識別出物件上的屬性
    * 屬性（Property）：物件上的靜態特性。即物件上擁有的特徵或是可表示的狀態（State）。名詞，例如：顏色或尺寸
3. 識別出物件上可操作的方法
    * 方法：物件上的動態特性。即物件本身可操作或供操作的介面。動詞，例如：寫程式、跑步
4. 產生物件實例
從物件定義書中產生物件實例，並以這些物件實例設計彼此間的交互行為以解決問題

範例：有一個帳戶，帳戶中有存款餘額，您可以對帳戶進行存款與提款的動作，並可以查詢以取得存款餘額。

* 識別出問題中的物件與屬性：
![](https://i.imgur.com/7laZCer.png)

* 識別出物件上可操作的方法：
![](https://i.imgur.com/7UihQE1.png)

* 從物件定義書中產生物件實例
![](https://i.imgur.com/zuADjjG.png)

* 類別建立的物件就是類別的實例(Instance)
>實例就是一個物件

## 使用 class 定義類別
* 類別（Class）：規格書
>使用類別定義出物件的規格書，之後根據類別來建構出一個個的物件，然後透過物件所提供的操作介面來與程式互動。

舉例：為「帳戶」這個物件定義了 Account 類別

範例：Account.java
```java=
public class Account {
    private String accountNumber;
    private double balance;

    public Account() {
        this("empty", 0.0);
    }

    public Account(String accountNumber, double balance) {
        this.accountNumber = accountNumber;
        this.balance = balance;
    }

    public String getAccountNumber() {
        return accountNumber;
    }

    public double getBalance() {
        return balance;
    }

    public void deposit(double money) {
        balance += money;
    }

    public double withdraw(double money) {
        balance -= money;
        return money;
    }
}
```
![](https://i.imgur.com/sO6vyc9.png)



### 類別宣告 (Class declaration)
:::info
```java=
[modifier] class class_identifier {
    // ..類別本體
}
```
* modifier 被使用來決定此類別相對於其它類別的存取權。modifier 可有可無，可以是 public、abstract、或是 final
* class 關鍵字告訴編譯器此程式區塊為一類別宣告
* class_identifier 是你給予類別的名稱
:::

* 在一個檔案中可以定義數個類別，但只能有一個類別被設定為 "public"，檔案名稱主檔名必須與這個 public 的類別同名
例如：
```java=
public class Account { // 檔案必須是Account.java
    // 實作內容 
}
class SomeClass {
    //實作內容
}
class OtherClass {
    //實作內容
}
```
* 宣告類別後，Java可以將類別當作資料型態，利用資料型態來宣告物件變數

範例：
![](https://i.imgur.com/sMRp3Kc.png)

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

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


* 基本原則：資訊的最小化公開
>儘量透過方法來操作物件，而不直接存取物件內部的資料成員

### 類別本體 (Class body)
* 類別本體中主要包括三個部份：變數( Variable )、建構式( Constructor )、方法( Method )

#### 變數 (Variable)/值域 (Field)/資料成員 (Data member)
* 變數即為表示物件的屬性(特徵)
* 宣告變數時依資料型態不同而有不同的預設值
![](https://i.imgur.com/2DaNvzu.png)
>類別變數在宣告時使用 private 關鍵字修飾，表示這個類別變數只能被在類別本體中定義的方法(Method)存取，外部物件無法直接存取，這樣的資料成員稱之為私用成員(Private member)。外部物件只能透過公開的(Public)操作介面才可以間接存取到私用成員(如果類別中有定義這樣的操作介面)。

>類別變數宣告時的權限修飾是可有可無的。預設是在同一個套件管理下的類別都可以存取該類別變數





#### 建構式/建構方法/建構子 ( Constructor )
* 與類別名稱同名
* 可以被重載(Overload)
* 作用：建構物件的同時，可以同時初始一些必要的資訊。例如：指定引數
* 不具有返回值(Return value)，也不用加上 void
* 建構物件時要使用 "new" 關鍵字
> 執行哪一個建構式,依照實例化時給定哪一種型態的引數而決定
* 預設建構式 (Default constructor)：公開且無參數

範例：
![](https://i.imgur.com/xVrr6pH.png)

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


#### 方法 (Method)
* 方法是物件擁有的操作能力(Operation)，也可表現出物件的行為(Behavior)
* 可以返回一個值，表示方法執行完畢後的運算結果
* 加上 **void**，表示這個方法執行完畢後不必返回任何值

## 類別方法 (Method)
### 定義方法
:::info
```java=
[modifier] type1 identifier(type2 param, ...) {
    [return data;]
}
```
* modifier：權限修飾。
>可以使用 public、protected、private 來修飾,分別將方法修飾為公開的、保護的或私用的
* type1：返回值型態。
 >可以使用基本資料型態，也可以是自定義的物件型態，如果方法執行完畢後不返回任何資料，則設定為 void
* identifier：方法名稱
* (type2 param, ...)：參數列。
>設定方法可接受的引數個數與型態
* 從方法中返回值時使用 return 關鍵字並加上要返回的數值或變數。返回的數值或變數之型態必須與type1 所設定的型態相同
:::

### static 靜態
用來宣告一個函數或者變數

* **特性一：永遠會是唯一值**
>永遠只佔著那一組記憶體空間。不管該類別被new幾個object，該值永遠都會是一樣的！
* **特性二：可以透過類別直接存取使用**
直接使用**類別.屬性名稱**或是**類別.方法名稱**
>不需要一直new物件出來

* 實例方法(非static的方法)可以直接使用static變數

* static方法不行直接呼叫使用非static變數及非static方法。若要使用，在static方法內new一個物件出來

範例：
```java=
class Ball {
    double radius;
    final double PI = 3.14159;
    ...
}
```
若建立多個Ball物件，那每個Ball物件都會有自己的radius與PI成員
![](https://i.imgur.com/htHOfLf.png)
```java=
class Ball {
    double radius;
    static final double PI = 3.141596;
    ...
}
```
被宣告為static的成員，不會讓個別物件擁有，而是屬於類別，如上定義後，如果建立多個Ball物件，每個Ball物件只會各自擁有radius
![](https://i.imgur.com/mTgbNyN.png)

* static方法或區塊中不能出現this關鍵字


>參考資料
>* [static 類別成員](https://openhome.cc/Gossip/Java/Static.html)
>* [關鍵字 this、static 的使用](http://www.codedata.com.tw/book/java-basic-source/ch11-3.htm)
>* [Java static,final 基本概念](http://blog.kenyang.net/2011/03/09/java-staticfinal)
>* [JAVA的static用法](http://b0212066.pixnet.net/blog/post/204120411-java%E7%9A%84static%E7%94%A8%E6%B3%95)
>* [使用 this](https://openhome.cc/Gossip/Java/This.html)

### 呼叫類別方法
:::info
```java=
[類別名稱].方法名稱(參數列);
```
:::

範例1：
![](https://i.imgur.com/ZOV2sPQ.png)

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


範例2：(呼叫其他類別的類別方法)
![](https://i.imgur.com/bMlvErB.png)

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


範例：
```java=
public class Hello{
    private String name;
 
    public Hello(){
        name = "nobody";
    }
 
    public Hello(String one){
        name = one;
    }
 
    public void hello(){
        System.out.print("Hello ");
        System.out.println(name);
    }
 
    public void setName(String one){
        name = one;
    }
}
```
### 類別方法的參數傳遞
* 正式參數/假參數：識別字，其角色如同變數，需要指定資料型態
* 實際參數：方法呼叫的參數，其運算結果的值需要和正式參數定義的資料型態相同

範例1：
![](https://i.imgur.com/g5KFMK8.png)


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

如果宣告的是基本型態參數，則呼叫方法時所給定的引數，會複製一份給參數；
如果宣告的是物件型態，則呼叫方法時所給定的物件，會被參數參考

範例2：
```java=
public class MethodDemo{
    public void primitiveParam(int para){
        para = 10;
    }
 
    public void referParam(int[] array){
        array[0] = 10;
    }
 
    public static void main(String[] args){
        int x = 5;
        int[] array = {1, 2, 3, 4, 5};
        MethodDemo demo = new MethodDemo();
 
        demo.primitiveParam(x);
        demo.referParam(array);
 
        System.out.println("x: " + x);
        System.out.print("array: ");
 
        for (int element : array){
            System.out.print(element);
            System.out.print(" ");
        }
        System.out.println();
    }
}
```
![](https://i.imgur.com/IiDCfsd.png)

### 類別方法的傳回值
* 使用「return」關鍵字
* 傳回值的型態需要與方法宣告的傳回值型態相同

範例1：(無傳回值)
![](https://i.imgur.com/wAZvvsl.png)

範例2：(有傳回值)
![](https://i.imgur.com/bOLOkAR.png)
  
![](https://i.imgur.com/wyb4Wla.png)

範例3：(有傳回值)
![](https://i.imgur.com/QHpDAUw.png)

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

範例4：無返回值、無參數的hello()方法
```java=
public void hello() {
    System.out.print("Hello ");
    System.out.println(name);
}
Hello hello = new Hello("Java");
hello.hello();
```
結果：螢幕上顯示"Hello Java"的文字


### 傳值或傳址參數
* 傳值：把變數值傳入方法，方法會另外配置記憶體儲存參數值，**不會變更原本呼叫的變數值**
	* **數值(int、double)、字元/字串(char、String)** 
* 傳址：把變數實際儲存的記憶體位置傳入，若在方法更改參數值，也會**變更原本呼叫的變數值**
	* **陣列(Array)**

範例： 
![](https://i.imgur.com/SXjcoDX.png)

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



### 類別變數和變數範圍
* Java語言的變數分為類別的成員變數、方法參數和區域變數
* static + 成員變數 >> 類別變數
>>不需要伴隨物件，自己就有意義了

1. 區域變數範圍：在方法內宣告的變數，只能在程式碼後使用（不包括宣告前），在方法外的程式碼並無法存取此變數。
2. 方法參數範圍：傳入方法的參數變數範圍是整個方法的程式區塊，在方法外的程式碼並無法存取。
3. 成員變數範圍：不論是static的類別變數或是沒有宣告static，整個類別的程式碼都可以存取此變數。

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

範例：
![](https://i.imgur.com/rKvY488.png)

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

範例：
![](https://i.imgur.com/dq4Uheq.png)

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

### 遞迴的階層函數（Recursive）
* 遞迴：一個問題的內涵是由本身所定義
1. 遞迴方法在每次呼叫時，都可以使問題範圍逐漸縮小
2. 遞迴方法需要擁有終止條件，以便結束的執行

範例：
![](https://i.imgur.com/iL5KUCE.png)
  
![](https://i.imgur.com/sIspdJj.png)

### Math數學類別的類別方法
* 在呼叫方法時需要指明類別Math

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

範例：
![](https://i.imgur.com/aRMQ7Qp.png)

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