###### 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);
}
}
```
>執行結果

# 繼承(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

* step 2 : 命名為相關名稱

* step 3 : 建立一個類別

* step 4 : import 套件

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