2019/0509/Java物件導向(函式)_儲存型態+回傳值+多載+自制+例外處理+this參照+存取+複合

https://matthung0807.blogspot.com/2018/02/java-overload.html

#前期提要

函式存取方式 三種 公開public 私有private 保護protected

##函式儲存記憶體型態

靜態Static

表示這個函式 為 靜態方法/類別函式

如果有這個宣告在編譯時就會佔有記憶體

不用透過關鍵字即可已被值接呼叫

###用法

一般(非類別)沒宣告為static靜態的 就必須透過建構式 new 配置

因為一般的則為動態的配置記憶體方式

然後以物件名稱.函式方法名稱(引述列)來呼叫

類別函式可以直接用函式名稱(引述列)來呼叫,或已類別名稱.函式方法名稱(引述列)來呼叫

###Static函式只能存取 static成員,即類別函式只能存取類別變數和類別方法函式,不能存取實例變數和實例方法函式

###Static函數只能存取static的變數使用static的方法

###動態靜態無法互相呼叫存取

##函式傳回值型別

以前沒有物件導向時就有了

函式型別

函式傳回 (return)值的資料型別

Ex void or int string …

函式沒有回傳值則型別為void 沒有回傳值

在函式內看不到return的關鍵字使用

權限 記憶體配置方式 函式名稱 參數列 參數名稱

Public static void main (string str)

##呼叫函式

函式名稱(參數, 參數…)

變數 = 函式名稱(參數, 參數…)

#函式呼叫參數狀態有兩種方式

傳值(pass by value

拷貝一份傳給對應參數

在函式執行過程永遠參照拷貝的那份最原本的

傳參照(pass by reference

起始參數位址傳遞給參數

如果在函式執行過程改變了那參數也會被改變

##傳值 (pass by reference

###範例 java12_9.java ( 一維陣列參數reference

印a陣列 印出 在另一個函數改變a

Math.sqrt ( 靜態方法可以直接呼叫

Class 一系列數學特定功能 ( 開根號等等 sqrt是裡面其中一種開根號方法

有點懶得打程式碼…

###老師的範例碼

居然可以讓

Mether跟原本庫的掛件靜態類別方法同名稱???只差在namespace不一樣

Public static void print (int x[]){System.out.print(x[i]+””)};

package com.example.java;

public class Java12_9 {

	public static void main(String[] args) {
		// TODO 自動產生的方法 Stub.

		int a[] = { 2, 4, 9, 16, 25, 36, 49, 64, 81 };
		print(a);
		sqrt(a);
		print(a);
				
	}
	
	public static void print(int x[]) {
		System.out.print("陣列內容為:");
		for (int i = 0; i < x.length; i++)
			System.out.print(x[i] + " ");
		System.out.println();
	}

	public static void sqrt(int x[]) {
		for (int i = 0; i < x.length; i++)
			x[i] = (int) Math.sqrt((double) x[i]);
	}

}

###範例Java12_10java (二維陣列參數 value / return值方法函數

一樣有點懶得打程式碼…

宣告一靜態函數 ( 對於char 變數來說是內部

裡面

宣告陣列int

宣告char

印出

宣告一靜態函數 (對於剛剛的char變數來說是外部

去改剛剛 宣告的 基礎型態char的值

印出 (外部被更動char不會被改變??

### 所以說 基礎參數型別 char 就是 value 方式傳參數值

主要是要說

先宣告一個印出函數

一個函數有return一個沒有但藉由參數reference達到與return相同效果

順道講矩陣相加

範例java12_10.java裡面有以下範例

##函式方法多載(method overloading)

多載(Overload)指在一個類別(class)中,定義多個名稱相同,但參數(Parameter)不同的方法(Method)。

使用同一個方法(函式)名稱

具備多種相似的功能

設計加法函式,讓它可以處理整數的相加,浮點數的相加,字串的相加,都是用add()這個函數的功能,只差在型態不一樣。

記得不同多載還要指定函式回傳值型態

( 然後要考慮value或reference (有點像是區域變數的概念???回傳值 沒回傳值

add(int x , inty)

string add(string x , string y)

char add(char x , char y)

###老師程式碼

package com.example.java;

public class Java12_10 {

	public static void main(String[] args) {
		// TODO 自動產生的方法 Stub.

		int a[][] = { { 1, 2, 3, 4, 5 },
				{ 6, 7, 8, 9, 10 } };
		int b[][] = { { 0, 1, 2, 3, 0 }, 
				{ 2, 1, 3, 3, 5 } };
		int c[][] = new int[a.length][a[1].length];
		
//		char d= 'c';
//		print('a', a);
//		print('b', b);
//		c = add(a, b);
//		add(a,b,c);
//		print(d, c);
//		System.out.println("d ="+d);
		
		int d=5,e=6,f=0;
		System.out.println("f ="+f);
		f=add(d,e);
		System.out.println("f ="+f);
	
				
	}
	
	public static void print(char c, int x[][]) {
		System.out.println(c + "陣列內容為:");
		for (int i = 0; i < x.length; i++) {
			for (int j = 0; j < x[i].length; j++)
				System.out.printf("%2d ", x[i][j]);
			System.out.println();
		}
		System.out.println();
		
		c = 'k';
		System.out.println("內部字元變數 c:"+c);
	}

	public static int[][] add(int x[][], int y[][]) {
		int z[][] = new int[x.length][x[1].length];
		for (int i = 0; i < x.length; i++) {
			for (int j = 0; j < x[i].length; j++)
				z[i][j] = x[i][j] + y[i][j];
		}
		return z;
	}

	public static void add(int x[][], int y[][], int z[][]) {
		for (int i = 0; i < x.length; i++) {
			for (int j = 0; j < x[i].length; j++)
				z[i][j] = x[i][j] + y[i][j];
		}
	}
	
	public static int add(int x,int y)
	{
		int z = x + y;
		return z;
	}
	
	public static String add(String x , String y) {
		String z = new String();
		z = x.concat(y);
		return z;
	} 
}

###範例java12_11.java

宣告一個無回傳值靜態函數,參數為字串陣列

並在裡面宣告值

###老師程式碼

package com.example.java;

public class Java12_11 {

	public static void main(String[] args) {
		// TODO 自動產生的方法 Stub.

		int i = 1, j = 2, k = 0;
		String s1 = "I love ";
		String s2 = "Java!";
		String s3 = new String();
		
		k = add(i, j);
		s3 = add(s1, s2);
		
		System.out.println("i=" + i + ", j=" + j + ", k=i+j=" + k);
		System.out.println("s1=\"" + s1 + "\", s2=\"" + s2 + "\", " + "s3=s1+s2=\"" + s3 + "\"");
		
	}
	
	public static int add(int i, int j) {
		return (i + j);
	}

	public static String add(String i, String j) {
		return (i + j);
	}
}

##自制類別與物件

###Time 類別”自製類別”案例研究

設計Time1類別會表示一日中的時刻

Private int 具有實體變數 hour minute second

用來表示時間格式

24小時制 hours 0-23 minutes seconds 0-59

Time1類別包含public方法setTime、toUniversalString、toString

這些方法也稱為類別,

提供給使用者public服務

public service或public介面( public interface (之後會在講

###程式碼範例 Time1.java

Private int hour; // 0-23

Private int minute; // 0-59

.

.

.

.

.

##自建構類別與物件的預設值

設計時若沒有軒告建構子,編譯器會提供預設版本建構子

每個int實體變數都會得到預設值0

也可以在建構的時候輸入

然後方式跟指定區域變數方式相同

###如果要讓自制類別物件更完整在出現例外時就要有例外處理。

利用throw 丟出例外處理 IllegalArgument

Ex 輸入時間範圍錯誤

方法setTime是一個public方法

宣告三個int參數用來設定時間

型態或範圍出錯時就出現例外處理訊息

可以利用 try catch 捕捉例外狀況 避免利用錯誤資料計算發生錯誤

###keyword

Throw敘述 會建立 一個 IllegalArgumentException物件

Throw跟new好像都是敘述 ? 結果查完後好像也是靜態類別之一 是關鍵字

就是一種語法的keyword

###程式碼如以下

package com.example.java;

public class Time1 {

	private int hour; // 0 - 23
	private int minute; // 0 - 59
	private int second; // 0 - 59

	public void setTime(int hour, int minute, int second) {

		if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60) {
			throw new IllegalArgumentException("輸入的  \"小時、分鐘、秒\" 超過範圍限制,發生位置(setTime.12)");
		}

		this.hour = hour;
		this.minute = minute;
		this.second = second;
	}

	public String toUniversalString() {
		return String.format("%02d:%02d:%02d", hour, minute, second);
	}

	public String toString() {
		return String.format("%d:%02d:%02d %s", ((hour == 0 || hour == 12) ? 12 : hour % 12), minute, second,
				(hour < 12 ? "AM" : "PM"));
	}

}

##題外話 如果不ctrl + f5清空暫存就會造成庫的版本引入錯誤

###Tien1Test.java

接著 new一個剛剛新增自制類別作測試

補圖

###程式碼如下

package com.example.java;

public class Time1Test {

	public static void main(String[] args) {
		// TODO 自動產生的方法 Stub.

		Time1 t1 = new Time1();
		displayTime("已建立新類別 Time1",t1);
		
		t1.setTime(11, 23, 54);
		System.out.println(t1.toUniversalString());
		
		try {
			t1.setTime(20, 23, 54);
			displayTime("已設定完成時間",t1);
		}catch (Exception ex){
			System.out.println("錯誤發生 : "+ex.getMessage());
		}

	}

	private static void displayTime(String header,Time1 t) 
	{
		System.out.printf("%s%n24小時制通用時間:%s%n12小時制時間:%s%n",header,t.toUniversalString(),t.toString());
		
	}
}

除了自己建立類別與物件外

也有內建的J SE8- Date/Time 物件

以下簡介內建類別與物件

在官方文件也有很清楚介紹

一般在撰寫程式的時候如果標準sdk內有內建的類別與物件就不會在自己去實作

###範例 MemberAccessTest.java

參數private

在除了類別內無法在外面引用與查詢看不到

###而且如果放開存取權會變成說有些在類別內的驗證程式碼會吃不到

變成值接指定 = 造成間接錯誤

這個好像會沒有程式碼 老師把他跟上一個寫在一起

##this參照

關鍵字this

存取指向自己的參照

This reference

如果class沒有寫

編譯器也會自己補進去

同一個java檔案,包含多個類別檔案時會分開類別檔.class

但保護層級的class必須在同一個.class檔案內,不然也是會發生錯誤

##範例thistest.java

一個檔案兩個class

Public class ThisTest {}

Class SimpleTime {}

一個java檔案裡面

只有一個可以被宣告為Public

第二個class在外部無法引用public內的東西

簡單來講 棕色跟藍色是不同東西

雖然都是容器,是變數

棕色是區域變數

藍色是類別變數

不寫也可以 編譯器會自己加上去

House

This.minute

This.second

### thistest.java程式碼

package com.example.java;

public class ThisTest {
	
	public static void main(String[] args) {
		SimpleTime t1 = new SimpleTime(16,20,15);
		System.out.println(t1.toUniversalString());
	} 
	
}

class SimpleTime {

	private int hour; // 0 - 23
	private int minute; // 0 - 59
	private int second; // 0 - 59

	public SimpleTime(int h, int m, int second) {

		if (h < 0 || h >= 24 || m < 0 || m >= 60 || second < 0 || second >= 60) {
			throw new IllegalArgumentException("輸入的  \"小時、分鐘、秒\" 超過範圍限制,發生位置(setTime.12)");
		}

		hour = h;
		this.minute = m;
		this.second = second;
	}

	public String toUniversalString() {
		return String.format("%02d:%02d:%02d", hour, minute, second);
	}

	public String toString() {
		return String.format("%d:%02d:%02d %s", ((hour == 0 || hour == 12) ? 12 : hour % 12), minute, second,
				(hour < 12 ? "AM" : "PM"));
	}

}

##Time2多載overloaded constructor建構子的案例

不同的簽名式signature塑造多種建構子

編譯器會將建構子呼叫中引述的數量、型別、順序與建構子宣告所指定的參數數量型別順序比對,呼叫正確的建構子

布林 初始預設值為 flase 參照則為 null

範例有五個 最後一個比較特殊 參數的本身就是他自己這個物件的型態

##建構式 不會有回傳型態 都是 void 因為是要給使用者 new的

有些比較細的內容可能要回去看ppt或影片

##存取函式/方法get set

多載的設定必須利用get與set

宣告說 使用者 如何 輸入參數與多載回傳參數

### 以上基本class設計結構都在以下 Time2.java裡面有範例

### Time2.java程式碼

package com.example.java;

public class Time2 {

	private int hour; // 0 - 23
	private int minute; // 0 - 59
	private int second; // 0 - 59
	private int millisecond; // 0 - 999 
	
	public Time2() {
		this(0, 0, 0, 0);
	}
	
	public Time2(int hour) {
		this(hour, 0, 0, 0);
	}
	
	public Time2(int hour,int minute) {
		this(hour, minute, 0, 0);
	}
		
	public Time2(int hour,int minute, int second) {
		this(hour, minute, second, 0);
	}
	
	public Time2(int hour, int minute, int second,int millisecond) {

		if (hour < 0 || hour >= 24)
			throw new IllegalArgumentException("輸入的  小時  必須在 0-23");
		
		if (minute < 0 || minute >= 60)
			throw new IllegalArgumentException("輸入的  分  必須在 0-59");
		
		if (second < 0 || second >= 60)
			throw new IllegalArgumentException("輸入的  秒  必須在 0-59");
		
		if (millisecond < 0 || millisecond >= 999)
			throw new IllegalArgumentException("輸入的  微秒  必須在 0-999");
		
		this.hour = hour;
		this.minute = minute;
		this.second = second;
		this.millisecond = millisecond;
	}

	public Time2(Time2 t) {

		this(t.getHour(), t.getMinute(), t.getSecond(), t.getMillisecond());
	}
	
	public void setHour(int hour) {
		if (hour < 0 || hour >= 24)
			throw new IllegalArgumentException("輸入的  小時  必須在 0-23");
		this.hour = hour;
	}
	
	public void setMinute(int minute) {
		if (minute < 0 || minute >= 60)
			throw new IllegalArgumentException("輸入的  分  必須在 0-59");
		this.minute = minute;
	}
	
	public void setSecond(int second) {
		if (second < 0 || second >= 60)
			throw new IllegalArgumentException("輸入的  秒  必須在 0-59");
		this.second = second;
	}
	
	public void setMillisecond(int millisecond) {
		if (millisecond < 0 || millisecond >= 999)
			throw new IllegalArgumentException("輸入的  微秒  必須在 0-999");
		this.millisecond = millisecond;
	}
	
	public int getHour() {
		return this.hour;
	}
	
	public int getMinute() {
		return this.minute;
	}
	
	public int getSecond() {
		return this.second;
	}
	
	public int getMillisecond() {
		return this.millisecond;
	}
	
	public String toUniversalString() {
		return String.format("%02d:%02d:%02d", hour, minute, second);
	}

	public String toString() {
		return String.format("%d:%02d:%02d %s", ((hour == 0 || hour == 12) ? 12 : hour % 12), minute, second,
				(hour < 12 ? "AM" : "PM"));
	}

}

###自建類別或物件

其實就是

宣告一些變數來放值

New些物件來用

多載些不同參數型態數量的類別或物件

提供些方法讓人用

最後再加上繼承、多型

接著老師在講

物件模組化

低耦合高內聚力

減少行數的

低維護成本

降低錯誤可能性

概念

##補充概念:

Set 又稱改變方法 mutator method

Get 又稱讀取方法accessor method

看ptt補

實作get set好像和

把實體變數宣告為public沒啥兩樣

1. 因為宣告為public他會沒辦法驗證參數

2. 具有隱私性 ( 商業邏輯可以藏在裡面

雖然get set 方法提供了存取 private 資料的途徑,但其實還是在現制的方法下

Set方法具有有效性的檢查

但並不會宣告private就自動出現,必須自己實作

內建的

判定方法predicate method

例如 ArrrayList的isEmpty方法

###接著 Time2Test.java

實作try呼叫剛剛做的函數 crath錯誤訊息物件

###程式碼

package com.example.java;

public class Time2Test {

	public static void main(String[] args) {
		// TODO 自動產生的方法 Stub.

		Time2 t1, t2, t3, t4, t5, t6;
		t1 = new Time2();
		t2 = new Time2(2);
		t3 = new Time2(21, 35);
		t4 = new Time2(21, 35, 46);
		t5 = new Time2(21, 35, 24, 55);

		try {
			t6 = new Time2(27, 35, 24, 55);
		} catch (IllegalArgumentException ex) {
			System.out.printf("錯誤發生! 物件初始畫錯誤 : %s %n%n", ex.getMessage());

		}
		
		displayTime("t1:時、分、秒、毫秒初始化為預設值 ", t1);
		displayTime("t2:指定小時,分、秒、毫秒初始化為預設值 ", t2);
		displayTime("t3:指定小時、分,秒、毫秒初始化為預設值 ", t3);
		displayTime("t4:指定小時、分、秒,毫秒初始化為預設值 ", t4);
		displayTime("t5:指定小時、分、秒、毫秒,初始化", t5);

	}

	private static void displayTime(String header, Time2 t) {
		System.out.printf("%s%n    %s%n    %s%n", header, t.toUniversalString(), t.toString());

	}
}

##複合 composition

類別可以包含指向其他類別物件的參照(參數),做為類別成員

擁有關係(has-arelationship

###案例Employee自訂類別表示特定員工身分 包含其他類別

###檔案Date.java類別 ( 老師之前實作了

需要紀錄時間所以指向Date物件(生日與雇用時間)

String其實也是類別型態的變數

###老師程式碼

package com.example.java;

public class Date {

	private int month; // 1-12
	private int day; // 1-31 based on month
	private int year; // any year

	private static final int[] daysPerMonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	public Date(int month, int day) {
		this(month, day, 2019);
	}

	public Date(int month, int day, int year) {
		if (month <= 0 || month > 12)
			throw new IllegalArgumentException("月份錯誤 (" + month + ") 必須在 1-12");

		if (day <= 0 || (day > daysPerMonth[month] && !(month == 2 && day == 29)))
			throw new IllegalArgumentException("日期錯誤 (" + day + ") 超過指定年、月的正常範圍");

		if (month == 2 && day == 29 && !(year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)))
			throw new IllegalArgumentException("日期錯誤 (" + day + ") 超過指定年、月的正常範圍");

		this.month = month;
		this.day = day;
		this.year = year;

		System.out.printf("Date 物件初始化成功: %s%n", this);
	}

	public String toString() {
		return String.format("%d/%d/%d", month, day, year);
	}

}

接著實作

###Employee.java 展示複合

package com.example.java;

public class Employee {

	private String firstName;
	private String lastName;
	private Date birthDate;
	private Date hireDate;

	public Employee(String firstName, String lastName, Date birthDate, Date hireDate) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.birthDate = birthDate;
		this.hireDate = hireDate;
	}

	public String toString() {
		return String.format("%s,%s-雇用日期: %s-出生日期: %s", lastName, firstName, hireDate, birthDate);
	}

}

###EmployeeTest.java 展示複合

package com.example.java;

public class EmployeeTest {

	public static void main(String[] args) {
		// TODO 自動產生的方法 Stub
		
	      Date birth = new  Date(7, 24, 2005);
	      Date hire = new  Date(3, 12, 2016);
	      Employee employee = new Employee("連杰", "李", birth, hire);

	      System.out.println(employee); 
	}

}

剛剛都是動態類別成員

##靜態類別成員 static 案例

某些其況下特定變數只有一個副本,供類別所有物件共用

此情況下就會使用static欄位 staticfield稱為類別變數class variable

Static變數會用來表示權類別性的資訊

呼叫方式

值接給參照(位址)

或是類別名稱加上.

該類別尚未有物件存在時便已存在執行時期因為編譯的時候就編譯了

下次設計自己的class 類別繼承階層

多型(Polymorphism)是指父類別可透過子類別衍伸成多種型態,而父類別為子類別的通用型態,再透過子類別可覆寫父類別的方法來達到多型的效果,也就是同樣的方法名稱會有多種行為。

感覺下次就會講多型因為跟繼承有關

沒手機照片無法拍 看ppt或影片吧

有少東西要看ptt

Last updated